scriptisto-2.2.0/.cargo_vcs_info.json0000644000000001360000000000100132400ustar { "git": { "sha1": "ba8b8a0fe5a755fffdfa3572c7cd3923017660dd" }, "path_in_vcs": "" }scriptisto-2.2.0/.github/ISSUE_TEMPLATE.md000064400000000000000000000002021046102023000160670ustar 00000000000000## Expected Behavior ## Actual Behavior ## Steps to Reproduce the Problem 1. 1. 1. ## Specifications - Version: - Platform:scriptisto-2.2.0/.github/PULL_REQUEST_TEMPLATE.md000064400000000000000000000002431046102023000171700ustar 00000000000000Fixes # > It's a good idea to open an issue first for discussion. - [ ] Tests pass - [ ] Appropriate changes to README are included in PRscriptisto-2.2.0/.github/workflows/on-push.yml000064400000000000000000000023231046102023000175410ustar 00000000000000name: On Push on: workflow_dispatch: push: branches: [ "master" ] pull_request: branches: [ "master" ] env: CARGO_TERM_COLOR: always jobs: clippy_check: runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v2 - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true components: clippy - name: Clippy check uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} args: --all-features build-and-test: runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v2 - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true components: clippy - name: Build uses: actions-rs/cargo@v1 with: command: build args: --release - name: Test uses: actions-rs/cargo@v1 with: command: test args: --release scriptisto-2.2.0/.github/workflows/on-release.yml000064400000000000000000000056601046102023000202110ustar 00000000000000name: On Release on: workflow_dispatch: push: tags: - "v*.*.*" env: CARGO_TERM_COLOR: always jobs: release: runs-on: ${{ matrix.os }} strategy: matrix: build: [linux, macos] include: - build: linux os: ubuntu-22.04 rust: stable target: x86_64-unknown-linux-musl - build: macos os: macos-12 rust: stable target: x86_64-apple-darwin steps: - name: Install Ubuntu tools if: matrix.os == 'ubuntu-22.04' run: sudo apt-get update && sudo apt-get install -y musl-tools rpm - name: Install Mac OS X tools if: matrix.build == 'macos' run: brew install coreutils - name: Checkout sources uses: actions/checkout@v2 - name: Install toolchain uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} target: ${{ matrix.target }} override: true - name: Build binary uses: actions-rs/cargo@v1 with: command: build args: --release --target ${{ matrix.target }} - name: Strip binary run: strip ./target/${{ matrix.target }}/release/scriptisto - name: Make bz2 run: | tar -cjvf ./scriptisto-${{ matrix.target }}.tar.bz2 --directory=./target/${{ matrix.target }}/release scriptisto sha256sum ./scriptisto-${{ matrix.target }}.tar.bz2 - name: Install tools from crates if: matrix.build == 'linux' uses: actions-rs/cargo@v1 with: command: install args: cargo-deb cargo-generate-rpm - name: Copy to standard location if: matrix.build == 'linux' run: | mkdir -p ./target/release cp ./target/${{ matrix.target }}/release/scriptisto ./target/release/scriptisto - name: Build RPM if: matrix.build == 'linux' run: | cargo generate-rpm --target ${{ matrix.target }} sha256sum ./target/${{ matrix.target }}/generate-rpm/*.rpm - name: Build DEB if: matrix.build == 'linux' run: | cargo deb --no-build --separate-debug-symbols --target ${{ matrix.target }} sha256sum ./target/${{ matrix.target }}/debian/*.deb - name: Release Linux uses: softprops/action-gh-release@v1 if: matrix.build == 'linux' && startsWith(github.ref, 'refs/tags/') with: append_body: true files: | ./scriptisto-${{ matrix.target }}.tar.bz2 ./target/${{ matrix.target }}/debian/*.deb ./target/${{ matrix.target }}/generate-rpm/*.rpm - name: Release Mac OS X uses: softprops/action-gh-release@v1 if: matrix.build == 'macos' && startsWith(github.ref, 'refs/tags/') with: append_body: true files: | ./scriptisto-${{ matrix.target }}.tar.bz2 scriptisto-2.2.0/.gitignore000064400000000000000000000000201046102023000140100ustar 00000000000000target **/*.swp scriptisto-2.2.0/AUTHORS000064400000000000000000000004661046102023000131060ustar 00000000000000# This is the list of Scriptisto authors for copyright purposes. # # This does not necessarily list everyone who has contributed code, since in # some cases, their employer may be the copyright holder. To see the full list # of contributors, see the revision history in source control. Google LLC Igor Petruk scriptisto-2.2.0/CODE_OF_CONDUCT.md000064400000000000000000000107371046102023000146370ustar 00000000000000# Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. This Code of Conduct also applies outside the project spaces when the Project Steward has a reasonable belief that an individual's behavior may have a negative impact on the project or its community. ## Conflict Resolution We do not believe that all conflict is bad; healthy debate and disagreement often yield positive results. However, it is never okay to be disrespectful or to engage in behavior that violates the project’s code of conduct. If you see someone violating the code of conduct, you are encouraged to address the behavior directly with those involved. Many issues can be resolved quickly and easily, and this gives people more control over the outcome of their dispute. If you are unable to resolve the matter for any reason, or if the behavior is threatening or harassing, report it. We are dedicated to providing an environment where participants feel welcome and safe. Reports should be directed to *Igor Petruk *, the Project Steward(s) for *Scriptisto*. It is the Project Steward’s duty to receive and address reported violations of the code of conduct. They will then work with a committee consisting of representatives from the Open Source Programs Office and the Google Open Source Strategy team. If for any reason you are uncomfortable reaching out the Project Steward, please email opensource@google.com. We will investigate every complaint, but you may not receive a direct response. We will use our discretion in determining when and how to follow up on reported incidents, which may range from not taking action to permanent expulsion from the project and project-sponsored spaces. We will notify the accused of the report and provide them an opportunity to discuss it before any action is taken. The identity of the reporter will be omitted from the details of the report supplied to the accused. In potentially harmful situations, such as ongoing harassment or threats to anyone's safety, we may take action without notice. ## Attribution This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html scriptisto-2.2.0/Cargo.lock0000644000000526610000000000100112250ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "anyhow" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi 0.1.19", "libc", "winapi", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "cc" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags 1.3.2", "clap_derive", "clap_lex", "indexmap 1.9.3", "once_cell", "strsim", "termcolor", "textwrap", ] [[package]] name = "clap_derive" version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck", "proc-macro-error", "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "clap_lex" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ "os_str_bytes", ] [[package]] name = "csv" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" dependencies = [ "csv-core", "itoa", "ryu", "serde", ] [[package]] name = "csv-core" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" dependencies = [ "memchr", ] [[package]] name = "dirs" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-next" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ "cfg-if", "dirs-sys-next", ] [[package]] name = "dirs-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", "redox_users", "windows-sys 0.48.0", ] [[package]] name = "dirs-sys-next" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", "winapi", ] [[package]] name = "encode_unicode" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "env_filter" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" dependencies = [ "log", ] [[package]] name = "env_logger" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" dependencies = [ "env_filter", "log", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", "winapi", ] [[package]] name = "errno-dragonfly" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ "cc", "libc", ] [[package]] name = "exec" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "886b70328cba8871bfc025858e1de4be16b1d5088f2ba50b57816f4210672615" dependencies = [ "errno", "libc", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "include_dir" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" dependencies = [ "include_dir_macros", ] [[package]] name = "include_dir_macros" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ "proc-macro2", "quote", ] [[package]] name = "indexmap" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", ] [[package]] name = "indexmap" version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.5", ] [[package]] name = "is-terminal" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi 0.3.9", "libc", "windows-sys 0.52.0", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.5.0", "libc", ] [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "md5" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "number_prefix" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "os_str_bytes" version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "prettytable-rs" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" dependencies = [ "csv", "encode_unicode", "is-terminal", "lazy_static", "term", "unicode-width", ] [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", "syn 1.0.109", "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", "version_check", ] [[package]] name = "proc-macro2" version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "redox_users" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", "thiserror", ] [[package]] name = "rustversion" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "scriptisto" version = "2.2.0" dependencies = [ "anyhow", "clap", "dirs", "env_logger", "exec", "include_dir", "log", "md5", "number_prefix", "prettytable-rs", "serde", "serde_derive", "serde_yaml", "users", "walkdir", ] [[package]] name = "serde" version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "serde_yaml" version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ "indexmap 2.2.6", "itoa", "ryu", "serde", "unsafe-libyaml", ] [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "term" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ "dirs-next", "rustversion", "winapi", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "textwrap" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unsafe-libyaml" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "users" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" dependencies = [ "libc", "log", ] [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.5", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm 0.52.5", "windows_aarch64_msvc 0.52.5", "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", "windows_i686_msvc 0.52.5", "windows_x86_64_gnu 0.52.5", "windows_x86_64_gnullvm 0.52.5", "windows_x86_64_msvc 0.52.5", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] name = "windows_i686_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" scriptisto-2.2.0/Cargo.toml0000644000000122100000000000100112320ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "scriptisto" version = "2.2.0" authors = [ "Google LLC", "Igor Petruk", ] description = "A language-agnostic \"shebang interpreter\" that enables you to write scripts in compiled languages." readme = "README.md" categories = [ "development-tools::build-utils", "command-line-utilities", ] license = "Apache-2.0" repository = "https://github.com/igor-petruk/scriptisto" [package.metadata.deb] assets = [ [ "target/release/scriptisto", "usr/bin/", "755", ], [ "LICENSE", "usr/share/doc/scriptisto/", "644", ], [ "README.md", "usr/share/doc/scriptisto/README", "644", ], [ "man/scriptisto.1", "usr/share/man/man1/scriptisto.1", "644", ], [ "man/scriptisto-build.1", "usr/share/man/man1/scriptisto-build.1", "644", ], [ "man/scriptisto-cache.1", "usr/share/man/man1/scriptisto-cache.1", "644", ], [ "man/scriptisto-cache-clean.1", "usr/share/man/man1/scriptisto-cache-clean.1", "644", ], [ "man/scriptisto-cache-get.1", "usr/share/man/man1/scriptisto-cache-get.1", "644", ], [ "man/scriptisto-cache-info.1", "usr/share/man/man1/scriptisto-cache-info.1", "644", ], [ "man/scriptisto-new.1", "usr/share/man/man1/scriptisto-new.1", "644", ], [ "man/scriptisto-template.1", "usr/share/man/man1/scriptisto-template.1", "644", ], [ "man/scriptisto-template-edit.1", "usr/share/man/man1/scriptisto-template-edit.1", "644", ], [ "man/scriptisto-template-import.1", "usr/share/man/man1/scriptisto-template-import.1", "644", ], [ "man/scriptisto-template-ls.1", "usr/share/man/man1/scriptisto-template-ls.1", "644", ], [ "man/scriptisto-template-rm.1", "usr/share/man/man1/scriptisto-template-rm.1", "644", ], ] section = "utils" [[package.metadata.generate-rpm.assets]] dest = "/usr/bin/" mode = "755" source = "target/release/scriptisto" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/doc/scriptisto/LICENSE" mode = "644" source = "LICENSE" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/doc/scriptisto/README.md" mode = "644" source = "README.md" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto.1" mode = "644" source = "man/scriptisto.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-build.1" mode = "644" source = "man/scriptisto-build.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-cache.1" mode = "644" source = "man/scriptisto-cache.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-cache-clean.1" mode = "644" source = "man/scriptisto-cache-clean.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-cache-get.1" mode = "644" source = "man/scriptisto-cache-get.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-cache-info.1" mode = "644" source = "man/scriptisto-cache-info.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-new.1" mode = "644" source = "man/scriptisto-new.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-template.1" mode = "644" source = "man/scriptisto-template.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-template-edit.1" mode = "644" source = "man/scriptisto-template-edit.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-template-import.1" mode = "644" source = "man/scriptisto-template-import.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-template-ls.1" mode = "644" source = "man/scriptisto-template-ls.1" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man1/scriptisto-template-rm.1" mode = "644" source = "man/scriptisto-template-rm.1" [package.metadata.rpm.cargo] buildflags = ["--release"] target = "x86_64-unknown-linux-musl" [package.metadata.rpm.targets.scriptisto] path = "/usr/bin/scriptisto" [dependencies.anyhow] version = "1" [dependencies.clap] version = "3" features = ["derive"] [dependencies.dirs] version = "5" [dependencies.env_logger] version = "0" default-features = false [dependencies.exec] version = "0.3" [dependencies.include_dir] version = "0.7" [dependencies.log] version = "0.4" [dependencies.md5] version = "0" [dependencies.number_prefix] version = "0.4" [dependencies.prettytable-rs] version = "0.10" [dependencies.serde] version = "1.0" [dependencies.serde_derive] version = "1.0" [dependencies.serde_yaml] version = "0.9" [dependencies.users] version = "0.11" [dependencies.walkdir] version = "2" scriptisto-2.2.0/Cargo.toml.orig000064400000000000000000000102041046102023000147140ustar 00000000000000# Copyright 2019 The Scriptisto Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. [package] name = "scriptisto" version = "2.2.0" edition = "2018" license = "Apache-2.0" description = "A language-agnostic \"shebang interpreter\" that enables you to write scripts in compiled languages." repository = "https://github.com/igor-petruk/scriptisto" readme = "README.md" categories = ["development-tools::build-utils", "command-line-utilities"] authors = [ "Google LLC", "Igor Petruk", ] [package.metadata.rpm.cargo] target = "x86_64-unknown-linux-musl" buildflags = ["--release"] [package.metadata.rpm.targets] scriptisto = { path = "/usr/bin/scriptisto" } [dependencies] dirs = '5' exec = '0.3' anyhow = '1' include_dir = '0.7' log = '0.4' serde='1.0' serde_derive='1.0' serde_yaml='0.9' md5="0" prettytable-rs="0.10" users="0.11" walkdir="2" number_prefix="0.4" clap = { version = "3", features = ["derive"] } [dependencies.env_logger] default-features = false version = '0' [package.metadata.deb] section = "utils" assets = [ ["target/release/scriptisto", "usr/bin/", "755"], ["LICENSE", "usr/share/doc/scriptisto/", "644"], ["README.md", "usr/share/doc/scriptisto/README", "644"], ["man/scriptisto.1", "usr/share/man/man1/scriptisto.1", "644"], ["man/scriptisto-build.1", "usr/share/man/man1/scriptisto-build.1", "644"], ["man/scriptisto-cache.1", "usr/share/man/man1/scriptisto-cache.1", "644"], ["man/scriptisto-cache-clean.1", "usr/share/man/man1/scriptisto-cache-clean.1", "644"], ["man/scriptisto-cache-get.1", "usr/share/man/man1/scriptisto-cache-get.1", "644"], ["man/scriptisto-cache-info.1", "usr/share/man/man1/scriptisto-cache-info.1", "644"], ["man/scriptisto-new.1", "usr/share/man/man1/scriptisto-new.1", "644"], ["man/scriptisto-template.1", "usr/share/man/man1/scriptisto-template.1", "644"], ["man/scriptisto-template-edit.1", "usr/share/man/man1/scriptisto-template-edit.1", "644"], ["man/scriptisto-template-import.1", "usr/share/man/man1/scriptisto-template-import.1", "644"], ["man/scriptisto-template-ls.1", "usr/share/man/man1/scriptisto-template-ls.1", "644"], ["man/scriptisto-template-rm.1", "usr/share/man/man1/scriptisto-template-rm.1", "644"], ] [package.metadata.generate-rpm] assets = [ {source="target/release/scriptisto", dest="/usr/bin/",mode= "755"}, {source="LICENSE", dest="/usr/share/doc/scriptisto/LICENSE", mode="644"}, {source="README.md", dest="/usr/share/doc/scriptisto/README.md", mode="644"}, {source="man/scriptisto.1", dest="/usr/share/man/man1/scriptisto.1", mode="644"}, {source="man/scriptisto-build.1", dest="/usr/share/man/man1/scriptisto-build.1", mode="644"}, {source="man/scriptisto-cache.1", dest="/usr/share/man/man1/scriptisto-cache.1", mode="644"}, {source="man/scriptisto-cache-clean.1", dest="/usr/share/man/man1/scriptisto-cache-clean.1", mode="644"}, {source="man/scriptisto-cache-get.1", dest="/usr/share/man/man1/scriptisto-cache-get.1", mode="644"}, {source="man/scriptisto-cache-info.1", dest="/usr/share/man/man1/scriptisto-cache-info.1", mode="644"}, {source="man/scriptisto-new.1", dest="/usr/share/man/man1/scriptisto-new.1", mode="644"}, {source="man/scriptisto-template.1", dest="/usr/share/man/man1/scriptisto-template.1", mode="644"}, {source="man/scriptisto-template-edit.1", dest="/usr/share/man/man1/scriptisto-template-edit.1", mode="644"}, {source="man/scriptisto-template-import.1", dest="/usr/share/man/man1/scriptisto-template-import.1", mode="644"}, {source="man/scriptisto-template-ls.1", dest="/usr/share/man/man1/scriptisto-template-ls.1", mode="644"}, {source="man/scriptisto-template-rm.1", dest="/usr/share/man/man1/scriptisto-template-rm.1", mode="644"}, ] scriptisto-2.2.0/LICENSE000064400000000000000000000261361046102023000130450ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. scriptisto-2.2.0/README.md000064400000000000000000000050401046102023000133060ustar 00000000000000# Scriptisto [![Latest Version](https://img.shields.io/crates/v/scriptisto.svg)](https://crates.io/crates/scriptisto) ![Build Status](https://github.com/igor-petruk/scriptisto/actions/workflows/on-push.yml/badge.svg) ![Crates.io License](https://img.shields.io/crates/l/scriptisto) ![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/cargo/scriptisto) ![GitHub top language](https://img.shields.io/github/languages/top/igor-petruk/scriptisto) ![Crates.io](https://img.shields.io/crates/d/scriptisto?label=Cargo.io%20downloads) ![GitHub All Releases](https://img.shields.io/github/downloads/igor-petruk/scriptisto/total?logo=Github&label=Github%20Release%20downloads) It is tool to enable writing one file scripts in languages that require compilation, dependencies fetching or preprocessing. It works as a "shebang" for those scripts, extracting build instructions from comments. If a script is changed, scriptisto rebuilds it and caches the result. If a script was already built, scriptisto immediately delegates to a binary with only <1 ms overhead. Builds in Docker are [available](https://github.com/igor-petruk/scriptisto/wiki/Writing-scripts#builds-in-docker). Advantages and use-cases are listed in the [Wiki](https://github.com/igor-petruk/scriptisto/wiki#advantages). ## Demo ```c #!/usr/bin/env scriptisto #include #include // scriptisto-begin // script_src: main.c // build_cmd: clang -O2 main.c `pkg-config --libs --cflags glib-2.0` -o ./script // scriptisto-end int main(int argc, char *argv[]) { gchar* user = g_getenv("USER"); printf("Hello, C! Current user: %s\n", user); return 0; } ``` ```shell $ chmod +x ./script.c $ ./script.c Hello, C! Current user: username ``` **Note:** some templates such as `rust` take more time to build during the first time. The default behaviour is to supress the build logs, so do not be discouraged that you do not immediately see any output. More info in the [wiki](https://github.com/igor-petruk/scriptisto/wiki/Running-scripts#build-logs). ## Installation Scriptisto is available as a prebuilt statically-linked standalone binary or distributions packages at [Releases](https://github.com/igor-petruk/scriptisto/releases) or at [Crates.io](https://crates.io/crates/scriptisto). Please proceed to the [Installation](https://github.com/igor-petruk/scriptisto/wiki/Installation) for instructions. ## Documentation Proceed to our [Wiki](https://github.com/igor-petruk/scriptisto/wiki). ## Disclaimer This is not an officially supported Google product. scriptisto-2.2.0/data/README.md000064400000000000000000000005021046102023000142150ustar 00000000000000# Resources Data from this directory is linked in inside of the binary. ## Script templates For convinience of distributing a single binary that requires no installation, files in `templates` directory are linked into the binary. They are stripped offile extensions and shown as templates via `scriptisto new` command. scriptisto-2.2.0/data/templates/c.c000075500000000000000000000005301046102023000153260ustar 00000000000000#!/usr/bin/env scriptisto #include #include // scriptisto-begin // script_src: main.c // build_cmd: clang -O2 main.c `pkg-config --libs --cflags glib-2.0` -o ./script // scriptisto-end int main(int argc, char* argv[]) { const gchar* user = g_getenv("USER"); printf("Hello, C! Current user: %s\n", user); return 0; } scriptisto-2.2.0/data/templates/chicken.scm000075500000000000000000000002221046102023000170460ustar 00000000000000#!/usr/bin/env scriptisto ; scriptisto-begin ; script_src: script.scm ; build_cmd: csc -O2 script.scm ; scriptisto-end (print "Hello, Scheme!") scriptisto-2.2.0/data/templates/cobol.cob000075500000000000000000000005111046102023000165220ustar 00000000000000#!/usr/bin/env scriptisto * scriptisto-begin * script_src: cobol.cob * build_cmd: cobc -x -o script ./cobol.cob * replace_shebang_with: ' * ' * scriptisto-end IDENTIFICATION DIVISION. PROGRAM-ID. hello. PROCEDURE DIVISION. DISPLAY "Hello, COBOL!". STOP RUN. scriptisto-2.2.0/data/templates/cpp.cc000075500000000000000000000005651046102023000160410ustar 00000000000000#!/usr/bin/env scriptisto #include #include // scriptisto-begin // script_src: main.cc // build_cmd: clang++ -O2 main.cc `pkg-config --libs --cflags glibmm-2.4` -o ./script // scriptisto-end int main(int argc, char *argv[]) { const auto user = Glib::getenv("USER"); std::cout << "Hello, C++! Current user: " << user << std::endl; return 0; } scriptisto-2.2.0/data/templates/crystal.cr000075500000000000000000000005261046102023000167540ustar 00000000000000#!/usr/bin/env scriptisto # scriptisto-begin # script_src: script.cr # build_cmd: shards build --production && strip ./bin/script # target_bin: ./bin/script # files: # - path: shard.yml # content: | # name: script # version: 0.1.0 # targets: # script: # main: script.cr # scriptisto-end puts "Hello, Crystal!" scriptisto-2.2.0/data/templates/csharp.cs000064400000000000000000000015011046102023000165430ustar 00000000000000#!/usr/bin/env scriptisto // scriptisto-begin // script_src: Program.cs // target_bin: bin/Release/net8.0/script // build_cmd: dotnet build -c Release script.csproj // files: // - path: script.csproj // content: | // // // Exe // net8.0 // enable // enable // // // scriptisto-end // See https://aka.ms/new-console-template for more information var name = Environment.GetEnvironmentVariable("USER"); Console.BackgroundColor = ConsoleColor.DarkBlue; Console.ForegroundColor = ConsoleColor.White; Console.Write("Hello"); Console.ResetColor(); Console.WriteLine($", {name}!"); scriptisto-2.2.0/data/templates/dart.dart000075500000000000000000000004371046102023000165540ustar 00000000000000#!/usr/bin/env scriptisto /* scriptisto-begin script_src: cli/main.dart build_cmd: dart compile exe "cli/main.dart" -o my-dart-program target_bin: ./my-dart-program scriptisto-end */ void main(List arguments) { print('Hello Dart, arguments=' + arguments.toString()); } scriptisto-2.2.0/data/templates/dart_multifile.dart000075500000000000000000000006431046102023000206250ustar 00000000000000#!/usr/bin/env scriptisto # This template is meant to compile whole Dart projects instead of a single file # # scriptisto-begin # script_src: dart_multifile_project/main.dart # build_in_script_dir: true # build_cmd: set -eu && dart compile exe "dart_multifile_project/main.dart" -o "${SCRIPTISTO_CACHE_DIR}/my-dart-program" # target_bin: my-dart-program # extra_src_paths: # - dart_multifile_project # scriptisto-end scriptisto-2.2.0/data/templates/dart_multifile_project/functions.dart000064400000000000000000000002221046102023000243510ustar 00000000000000// This file will also be checked for changes by scriptisto import 'dart:io'; String getWorkingDirectory() { return Directory.current.path; } scriptisto-2.2.0/data/templates/dart_multifile_project/main.dart000064400000000000000000000002431046102023000232700ustar 00000000000000import 'functions.dart'; void main(List arguments) { print( 'Hello Dart, arguments=$arguments getWorkingDirectory()=${getWorkingDirectory()}'); } scriptisto-2.2.0/data/templates/deno.ts000075500000000000000000000005241046102023000162400ustar 00000000000000#!/usr/bin/env scriptisto // scriptisto-begin // script_src: script.ts // build_cmd: deno bundle script.ts // target_bin: ./script.bundle.js // target_interpreter: /usr/bin/env deno --no-prompt // scriptisto-end import { yellow, bold } from "https://deno.land/std/fmt/colors.ts"; console.log(yellow(bold("Hello, TypeScript on Deno!"))); scriptisto-2.2.0/data/templates/docker000075500000000000000000000007461046102023000161430ustar 00000000000000#!/usr/bin/env scriptisto # scriptisto-begin # script_src: internal.sh # build_cmd: docker build -t docker-script . && chmod +x ./external.sh # target_bin: ./external.sh # files: # - path: external.sh # content: | # #!/bin/bash # docker run -i --rm docker-script # - path: Dockerfile # content: | # FROM alpine # COPY internal.sh /internal.sh # CMD sh /internal.sh # scriptisto-end echo -n "Hello, Docker! Alpine Linux version: " cat /etc/alpine-release scriptisto-2.2.0/data/templates/docker-c.c000075500000000000000000000010561046102023000165770ustar 00000000000000#!/usr/bin/env scriptisto #include #include // scriptisto-begin // script_src: main.c // build_cmd: clang -static -O2 main.c `pkg-config --libs --cflags glib-2.0` -o ./script // docker_build: // src_mount_dir: /src // dockerfile: | // FROM alpine // WORKDIR /src // RUN apk add glib-static glib-dev clang libc-dev build-base binutils pkgconfig // scriptisto-end int main(int argc, char* argv[]) { const gchar* user = g_getenv("USER"); printf("Hello, C built in Docker! Current user: %s\n", user); return 0; } scriptisto-2.2.0/data/templates/docker-ocaml.ml000075500000000000000000000011321046102023000176310ustar 00000000000000#!/usr/bin/env scriptisto (* scriptisto-begin script_src: script.ml build_cmd: cd /src/ && sudo chown -R $(id -u) /src && opam exec -- dune build script.exe target_bin: ./_build/default/script.exe docker_build: dockerfile: | FROM ocaml/opam2:alpine RUN sudo apk add m4 && opam install -y lwt src_mount_dir: /src files: - path: dune content: (executable (name script) (libraries lwt.unix)) - path: dune-workspace content: | (lang dune 1.1) (env (_ (flags -cclib -static))) scriptisto-end *) Lwt_main.run (Lwt_io.printf "Hello, OCaml!\n") scriptisto-2.2.0/data/templates/docker-reason.re000075500000000000000000000011461046102023000200300ustar 00000000000000#!/usr/bin/env scriptisto /* scriptisto-begin script_src: script.re build_cmd: cd /src/ && sudo chown -R $(id -u) /src && opam exec -- dune build script.exe target_bin: ./_build/default/script.exe docker_build: dockerfile: | FROM ocaml/opam2:alpine RUN sudo apk add m4 && opam install -y lwt reason src_mount_dir: /src files: - path: dune content: (executable (name script) (libraries lwt.unix)) - path: dune-workspace content: | (lang dune 1.1) (env (_ (flags -cclib -static))) scriptisto-end */ Lwt_main.run (Lwt_io.printf ("Hello, ReasonML!\n")); scriptisto-2.2.0/data/templates/docker-rust.rs000075500000000000000000000011701046102023000175510ustar 00000000000000#!/usr/bin/env scriptisto // scriptisto-begin // script_src: src/main.rs // build_cmd: "cargo build --release && cp ./target/*musl*/release/script ./target/script" // target_bin: ./target/script // docker_build: // dockerfile: FROM clux/muslrust // src_mount_dir: /volume // extra_args: [-v,cargo-cache:/root/.cargo/registry] // files: // - path: Cargo.toml // content: | // package = { name = "script", version = "0.1.0", edition = "2018"} // [dependencies] // rand="*" // scriptisto-end fn main() { println!( "Hello, Rust built in Docker! Random: {}", rand::random::() ); } scriptisto-2.2.0/data/templates/elixir.ex000075500000000000000000000007661046102023000166050ustar 00000000000000#!/usr/bin/env scriptisto # scriptisto-begin # script_src: lib/script.ex # build_cmd: MIX_ENV=prod mix escript.build # files: # - path: mix.exs # content: | # defmodule Script.MixProject do # use Mix.Project # def project do # [ # app: :script, # version: "0.1.0", # elixir: "~> 1.8", # escript: [main_module: Script.CLI], # ] # end # end # scriptisto-end defmodule Script.CLI do def main(_) do IO.puts "Hello, Elixir!" end end scriptisto-2.2.0/data/templates/fortran.f90000075500000000000000000000003271046102023000167370ustar 00000000000000#!/usr/bin/env scriptisto ! scriptisto-begin ! script_src: script.f90 ! build_cmd: gfortran script.f90 -o ./script ! scriptisto-end program script implicit none print *, "Hello, Fortran!" end program script scriptisto-2.2.0/data/templates/go.go000075500000000000000000000006441046102023000157020ustar 00000000000000#!/usr/bin/env scriptisto package main // scriptisto-begin // script_src: main.go // build_once_cmd: go mod tidy // build_cmd: go build -o script // replace_shebang_with: // // files: // - path: go.mod // content: | // module example.com/a/b // require ( // github.com/fatih/color v1.13.0 // ) // scriptisto-end import "github.com/fatih/color" func main() { color.Yellow("Hello, Go!") } scriptisto-2.2.0/data/templates/haskell.hs000075500000000000000000000002701046102023000167200ustar 00000000000000#!/usr/bin/env scriptisto -- scriptisto-begin -- script_src: script.hs -- build_cmd: ghc -O -o script script.hs && strip ./script -- scriptisto-end main = putStrLn "Hello, Haskell!" scriptisto-2.2.0/data/templates/java.java000075500000000000000000000015701046102023000165310ustar 00000000000000#!/usr/bin/env scriptisto // scriptisto-begin // script_src: src/main/java/script/Script.java // build_cmd: gradle build && tar xf ./build/distributions/java.java.tar --strip 1 -C . // target_bin: ./bin/java.java // // files: // - path: build.gradle // content: | // apply plugin: 'java' // apply plugin: 'application' // mainClassName = 'script.Script' // tasks.distZip.enabled = false // repositories { // mavenCentral() // } // dependencies { // compile 'ch.qos.logback:logback-classic:1.2.3' // } // scriptisto-end package script; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Script{ private static final Logger logger = LoggerFactory.getLogger(Script.class); public static void main(String[] args) { logger.debug("Hello, Java! Current Date : {}", new Date()); } } scriptisto-2.2.0/data/templates/node.js000075500000000000000000000011151046102023000162230ustar 00000000000000#!/usr/bin/env scriptisto // scriptisto-begin // script_src: script.js // build_once_cmd: npm install // target_bin: ./script.js // target_interpreter: /usr/bin/env node // files: // - path: package.json // content: | // { "dependencies": { "yargs": "^14.2.0" } } // scriptisto-end argv = require('yargs') .usage('Usage: $0 [options]') .command('script', 'Example script') .alias('i', 'input').nargs('i', 1).describe('i', 'Example input') .help('h').alias('h', 'help') .argv; console.log("Hello, JavaScript on Node!. Input: " + (argv.input || "")); scriptisto-2.2.0/data/templates/ocaml.ml000075500000000000000000000004611046102023000163700ustar 00000000000000#!/usr/bin/env scriptisto (* scriptisto-begin script_src: script.ml build_cmd: dune build script.exe target_bin: ./_build/default/script.exe files: - path: dune content: (executable (name script) (libraries lwt.unix)) scriptisto-end *) Lwt_main.run (Lwt_io.printf "Hello, OCaml!\n") scriptisto-2.2.0/data/templates/pascal.pp000075500000000000000000000002661046102023000165520ustar 00000000000000#!/usr/bin/env scriptisto // scriptisto-begin // script_src: script.pp // build_cmd: fpc -O2 script.pp // scriptisto-end program script; begin writeln('Hello, Pascal!'); end. scriptisto-2.2.0/data/templates/python-mypy.py000075500000000000000000000010731046102023000176320ustar 00000000000000#!/usr/bin/env scriptisto # scriptisto-begin # script_src: script.py # build_cmd: mypy script.py && python3 -m compileall . # target_interpreter: /usr/bin/env python3 # target_bin: ./script.py # scriptisto-end import argparse from typing import Optional def print_hello(input: Optional[int]): msg = "Hello, Python! Input: %d" % (input or 0) print(msg) def main(): parser = argparse.ArgumentParser() parser.add_argument("--input", type=int, help="Example input.") args = parser.parse_args() print_hello(args.input) if __name__== "__main__": main() scriptisto-2.2.0/data/templates/python-pip.py000075500000000000000000000015421046102023000174250ustar 00000000000000#!/usr/bin/env scriptisto # scriptisto-begin # script_src: script.py # build_once_cmd: virtualenv -p python3 . && . ./bin/activate && pip install mypy termcolor # build_cmd: . ./bin/activate && mypy script.py && python3 -m compileall . && chmod +x ./run.sh # target_bin: ./run.sh # files: # - path: run.sh # content: | # #!/bin/sh # export DIR=$(dirname $0) # . $DIR/bin/activate # python3 $DIR/script.py $@ # scriptisto-end import argparse from termcolor import colored, cprint from typing import Optional def print_hello(input: Optional[int]): msg = "Hello, Python! Input: %d" % (input or 0) cprint(msg, 'green') def main(): parser = argparse.ArgumentParser() parser.add_argument("--input", type=int, help="Example input.") args = parser.parse_args() print_hello(args.input) if __name__== "__main__": main() scriptisto-2.2.0/data/templates/racket.rkt000075500000000000000000000004001046102023000167270ustar 00000000000000#!/usr/bin/env scriptisto ; scriptisto-begin ; script_src: ./script.rkt ; build_cmd: raco make script.rkt ; target_bin: ./compiled/script_rkt.zo ; target_interpreter: /usr/bin/env racket -t ; scriptisto-end #lang racket/base (displayln "Hello, Racket!") scriptisto-2.2.0/data/templates/reasonml.re000075500000000000000000000004671046102023000171210ustar 00000000000000#!/usr/bin/env scriptisto /* scriptisto-begin script_src: script.re build_cmd: dune build script.exe target_bin: ./_build/default/script.exe files: - path: dune content: (executable (name script) (libraries lwt.unix)) scriptisto-end */ Lwt_main.run (Lwt_io.printf ("Hello, ReasonML!\n")); scriptisto-2.2.0/data/templates/rust.rs000075500000000000000000000012441046102023000163060ustar 00000000000000#!/usr/bin/env scriptisto // scriptisto-begin // script_src: src/main.rs // build_cmd: cargo build --release && strip ./target/release/script // target_bin: ./target/release/script // files: // - path: Cargo.toml // content: | // package = { name = "script", version = "0.1.0", edition = "2018"} // [dependencies] // clap={version="4", features=["derive"]} // scriptisto-end use clap::Parser; #[derive(Debug, Parser)] #[command(name = "script", about = "A script.")] struct Opt { /// Example input #[arg(short, long)] input: Option, } fn main() { let opt = Opt::parse(); println!("Hello, Rust! Command line options: {:?}", opt); } scriptisto-2.2.0/data/templates/sbcl.lisp000075500000000000000000000006421046102023000165600ustar 00000000000000#!/usr/bin/env scriptisto ; scriptisto-begin ; script_src: script.lisp ; build_cmd: chmod +x build.lisp && ./build.lisp ; files: ; - path: build.lisp ; content: | ; #!/usr/bin/sbcl --script ; (load "script.lisp") ; (sb-ext:save-lisp-and-die "script" ; :executable t ; :toplevel 'main) ; scriptisto-end (defun main () (format t "Hello, Common Lisp!~%")) scriptisto-2.2.0/data/templates/zig.zig000075500000000000000000000003471046102023000162520ustar 00000000000000#!/usr/bin/env scriptisto // scriptisto-begin // script_src: script.zig // build_cmd: zig build-exe script.zig // scriptisto-end const std = @import("std"); pub fn main() anyerror!void { std.log.info("Hello, World!", .{}); } scriptisto-2.2.0/man/scriptisto-build.1000064400000000000000000000011551046102023000161670ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-build 1 "scriptisto-build " .SH NAME scriptisto\-build \- Build a script without running .SH SYNOPSIS \fBscriptisto build\fR [\fB\-b\fR|\fB\-\-build\-mode\fR] [\fB\-h\fR|\fB\-\-help\fR] <\fISCRIPT_SRC\fR> .SH DESCRIPTION Build a script without running .SH OPTIONS .TP \fB\-b\fR, \fB\-\-build\-mode\fR=\fIBUILD_MODE\fR Build mode. If unset, only builds if necessary. "source" \- to rebuild each time. "full" to fully re\-fetch Docker image and run `build_once_cmd` .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP <\fISCRIPT_SRC\fR> A path to a script to build scriptisto-2.2.0/man/scriptisto-cache-clean.1000064400000000000000000000011451046102023000172120ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-cache-clean 1 "scriptisto-cache-clean " .SH NAME scriptisto\-cache\-clean \- Clean the cache for a particular script. Removes the cache directory. Removes the Docker image/volume if they exist, but does not prune .SH SYNOPSIS \fBscriptisto cache clean\fR [\fB\-h\fR|\fB\-\-help\fR] <\fIFILE\fR> .SH DESCRIPTION Clean the cache for a particular script. Removes the cache directory. Removes the Docker image/volume if they exist, but does not prune .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP <\fIFILE\fR> A filename of the script file. scriptisto-2.2.0/man/scriptisto-cache-get.1000064400000000000000000000007421046102023000167110ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-cache-get 1 "scriptisto-cache-get " .SH NAME scriptisto\-cache\-get \- Shows a particular item from "info" by name .SH SYNOPSIS \fBscriptisto cache get\fR [\fB\-h\fR|\fB\-\-help\fR] <\fINAME\fR> <\fIFILE\fR> .SH DESCRIPTION Shows a particular item from "info" by name .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP <\fINAME\fR> An item name, e.g. cache_path. .TP <\fIFILE\fR> A filename of the script file. scriptisto-2.2.0/man/scriptisto-cache-info.1000064400000000000000000000007071046102023000170660ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-cache-info 1 "scriptisto-cache-info " .SH NAME scriptisto\-cache\-info \- Shows information about the cache directory for the script .SH SYNOPSIS \fBscriptisto cache info\fR [\fB\-h\fR|\fB\-\-help\fR] <\fIFILE\fR> .SH DESCRIPTION Shows information about the cache directory for the script .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP <\fIFILE\fR> A filename of the script file. scriptisto-2.2.0/man/scriptisto-cache.1000064400000000000000000000013651046102023000161360ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-cache 1 "scriptisto-cache " .SH NAME scriptisto\-cache \- Build cache operations .SH SYNOPSIS \fBscriptisto cache\fR [\fB\-h\fR|\fB\-\-help\fR] <\fIsubcommands\fR> .SH DESCRIPTION Build cache operations .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .SH SUBCOMMANDS .TP scriptisto\-cache\-info(1) Shows information about the cache directory for the script .TP scriptisto\-cache\-clean(1) Clean the cache for a particular script. Removes the cache directory. Removes the Docker image/volume if they exist, but does not prune .TP scriptisto\-cache\-get(1) Shows a particular item from "info" by name .TP scriptisto\-cache\-help(1) Print this message or the help of the given subcommand(s) scriptisto-2.2.0/man/scriptisto-new.1000064400000000000000000000011301046102023000156520ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-new 1 "scriptisto-new " .SH NAME scriptisto\-new \- Prints an example starting script in a programming language of your choice .SH SYNOPSIS \fBscriptisto new\fR [\fB\-h\fR|\fB\-\-help\fR] [\fITEMPLATE_NAME\fR] .SH DESCRIPTION Prints an example starting script in a programming language of your choice .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP [\fITEMPLATE_NAME\fR] If specified, determines a language. Example usage: "scriptisto new | tee new\-script". If not specified, "new" lists available templates. scriptisto-2.2.0/man/scriptisto-template-edit.1000064400000000000000000000007711046102023000176310ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-template-edit 1 "scriptisto-template-edit " .SH NAME scriptisto\-template\-edit \- Opens an editor to modify an existing template, nice for quick edits .SH SYNOPSIS \fBscriptisto template edit\fR [\fB\-h\fR|\fB\-\-help\fR] <\fITEMPLATE_NAME\fR> .SH DESCRIPTION Opens an editor to modify an existing template, nice for quick edits .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP <\fITEMPLATE_NAME\fR> A name of the template to edit scriptisto-2.2.0/man/scriptisto-template-import.1000064400000000000000000000007211046102023000202110ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-template-import 1 "scriptisto-template-import " .SH NAME scriptisto\-template\-import \- Imports a template from file .SH SYNOPSIS \fBscriptisto template import\fR [\fB\-h\fR|\fB\-\-help\fR] <\fIFILE\fR> .SH DESCRIPTION Imports a template from file .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP <\fIFILE\fR> A filename of the script file. Extension will be stripped for the template name. scriptisto-2.2.0/man/scriptisto-template-ls.1000064400000000000000000000004761046102023000173240ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-template-ls 1 "scriptisto-template-ls " .SH NAME scriptisto\-template\-ls \- List all templates .SH SYNOPSIS \fBscriptisto template ls\fR [\fB\-h\fR|\fB\-\-help\fR] .SH DESCRIPTION List all templates .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information scriptisto-2.2.0/man/scriptisto-template-rm.1000064400000000000000000000007471046102023000173250ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-template-rm 1 "scriptisto-template-rm " .SH NAME scriptisto\-template\-rm \- Remove a custom template or reset it to the built\-in contents .SH SYNOPSIS \fBscriptisto template rm\fR [\fB\-h\fR|\fB\-\-help\fR] <\fITEMPLATE_NAME\fR> .SH DESCRIPTION Remove a custom template or reset it to the built\-in contents .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP <\fITEMPLATE_NAME\fR> A name of the template to remove scriptisto-2.2.0/man/scriptisto-template.1000064400000000000000000000014021046102023000166760ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto-template 1 "scriptisto-template " .SH NAME scriptisto\-template \- Manage custom script templates .SH SYNOPSIS \fBscriptisto template\fR [\fB\-h\fR|\fB\-\-help\fR] <\fIsubcommands\fR> .SH DESCRIPTION Manage custom script templates .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .SH SUBCOMMANDS .TP scriptisto\-template\-import(1) Imports a template from file .TP scriptisto\-template\-edit(1) Opens an editor to modify an existing template, nice for quick edits .TP scriptisto\-template\-rm(1) Remove a custom template or reset it to the built\-in contents .TP scriptisto\-template\-ls(1) List all templates .TP scriptisto\-template\-help(1) Print this message or the help of the given subcommand(s) scriptisto-2.2.0/man/scriptisto.1000064400000000000000000000016431046102023000150740ustar 00000000000000.ie \n(.g .ds Aq \(aq .el .ds Aq ' .TH scriptisto 1 "scriptisto " .SH NAME scriptisto \- A \*(Aqshebang\-interpreter\*(Aq for compiled languages .SH SYNOPSIS \fBscriptisto\fR [\fB\-h\fR|\fB\-\-help\fR] .TP \fBscriptisto\fR [\fISCRIPT\fR] .TP \fBscriptisto\fR [\fIsubcommands\fR] .SH DESCRIPTION A \*(Aqshebang\-interpreter\*(Aq for compiled languages .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Print help information .TP [\fISCRIPT\fR] A path for to a script to run and additional arguments passed to this script. A script path must start with \*(Aq.\*(Aq or \*(Aq/\*(Aq .SH SUBCOMMANDS .TP scriptisto\-cache(1) Build cache operations .TP scriptisto\-new(1) Prints an example starting script in a programming language of your choice .TP scriptisto\-template(1) Manage custom script templates .TP scriptisto\-build(1) Build a script without running .TP scriptisto\-help(1) Print this message or the help of the given subcommand(s) scriptisto-2.2.0/src/build.rs000064400000000000000000000303361046102023000142710ustar 00000000000000// Copyright 2019 The Scriptisto Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use anyhow::{anyhow, Context, Result}; use log::debug; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use crate::cfg; use crate::common; use crate::opt; pub const SCRIPTISTO_CACHE_DIR_VAR: &str = "SCRIPTISTO_CACHE_DIR"; pub const SCRIPTISTO_SOURCE_DIR_VAR: &str = "SCRIPTISTO_SOURCE_DIR"; pub const SCRIPTISTO_SOURCE_VAR: &str = "SCRIPTISTO_SOURCE"; fn docker_prefix(script_cache_path: &Path) -> Result { Ok(format!( "scriptisto-{}-{:x}", script_cache_path .file_name() .ok_or_else(|| anyhow!("BUG: invalid script_cache_path={:?}", script_cache_path))? .to_string_lossy(), md5::compute(script_cache_path.to_string_lossy().as_bytes()) )) } pub fn docker_image_name(script_cache_path: &Path) -> Result { docker_prefix(script_cache_path) } pub fn docker_volume_name(script_cache_path: &Path) -> Result { let docker_prefix = docker_prefix(script_cache_path)?; Ok(format!("{}-src", docker_prefix)) } fn docker_create_volume( volume_name: &str, script_cache_path: &Path, stderr_mode: Stdio, ) -> Result<()> { let mut build_vol_cmd = Command::new("docker"); build_vol_cmd.arg("volume").arg("create").arg(volume_name); common::run_command(script_cache_path, build_vol_cmd, stderr_mode)?; Ok(()) } fn docker_volume_cmd( volume_name: &str, script_cache_path: &Path, run_as_current_user: bool, cmd: &str, stderr_mode: Stdio, ) -> Result<()> { let mut vol_cmd = Command::new("docker"); vol_cmd.args(["run", "-t", "--rm"]); if run_as_current_user { vol_cmd.args(["-u", &format!("{}", users::get_current_uid())]); } vol_cmd.args([ "-v", &format!("{}:/vol", &volume_name), "-v", &format!("{}:/src", &script_cache_path.to_string_lossy()), "busybox", "sh", "-c", cmd, ]); common::run_command(script_cache_path, vol_cmd, stderr_mode)?; Ok(()) } fn run_build_command( cfg: &cfg::BuildSpec, script_path: &Path, script_cache_path: &Path, first_run: bool, build_mode: opt::BuildMode, stderr_mode: F, ) -> Result<()> where F: Fn() -> Stdio, { if first_run || build_mode == opt::BuildMode::Full { if let Some(build_once_cmd) = &cfg.build_once_cmd { let mut cmd = Command::new("/bin/sh"); cmd.arg("-c").arg(build_once_cmd); common::run_command(script_cache_path, cmd, stderr_mode())?; } } if let Some(build_cmd) = &cfg.build_cmd { match &cfg.docker_build { // TODO: Do better validation for empty dockerfile, but not-empty docker_build. Some(docker_build) if docker_build.dockerfile.is_some() => { // Write Dockerfile. let tmp_dockerfile_name = "Dockerfile.scriptisto"; common::write_bytes( script_cache_path, &PathBuf::from(&tmp_dockerfile_name), docker_build.dockerfile.clone().unwrap().as_bytes(), )?; // Create and populate sources volume. let src_docker_volume = docker_volume_name(script_cache_path)?; docker_create_volume(&src_docker_volume, script_cache_path, stderr_mode())?; docker_volume_cmd( &src_docker_volume, script_cache_path, false, "cp -rf /src/* /vol/", stderr_mode(), )?; // Build temporary image. let tmp_docker_image = docker_image_name(script_cache_path)?; let mut build_im_cmd = Command::new("docker"); build_im_cmd.arg("build"); if build_mode == opt::BuildMode::Full { build_im_cmd.arg("--no-cache"); } build_im_cmd .arg("-t") .arg(&tmp_docker_image) .arg("--label") .arg(format!( "scriptisto-cache-path={}", script_cache_path.to_string_lossy() )) .arg("-f") .arg(tmp_dockerfile_name) .arg("."); common::run_command(script_cache_path, build_im_cmd, stderr_mode())?; // Build binary in Docker. let mut cmd = Command::new("docker"); cmd.arg("run") .arg("-t") .arg("--rm") .arg("--env") .arg(format!( "{}={}", SCRIPTISTO_SOURCE_VAR, &script_path.to_string_lossy() )); if let Some(src_mount_dir) = &docker_build.src_mount_dir { cmd.arg("-v") .arg(format!("{}:{}", src_docker_volume, src_mount_dir)); } cmd.args(docker_build.extra_args.iter()) .arg(tmp_docker_image) .arg("sh") .arg("-c") .arg(build_cmd); common::run_command(script_cache_path, cmd, stderr_mode())?; // Extract target_bin back to host. let mut vol_path = PathBuf::from("/vol"); vol_path.push(&cfg.target_bin); let mut src_path = PathBuf::from("/src"); src_path.push(&cfg.target_bin); docker_volume_cmd( &src_docker_volume, script_cache_path, true, &format!( "mkdir -p $(dirname {}) && cp -rf {} {}", src_path.to_string_lossy(), vol_path.to_string_lossy(), src_path.to_string_lossy(), ), stderr_mode(), )?; } // Non-Docker build. _ => { let script_dir = match script_path.parent() { None => { return Err(anyhow!( "Failed to look up parent directory of {:?}", script_path )); } Some(p) => p, }; let mut cmd = Command::new("/bin/sh"); cmd.arg("-c") .arg(build_cmd) .env(SCRIPTISTO_CACHE_DIR_VAR, script_cache_path) .env(SCRIPTISTO_SOURCE_DIR_VAR, script_dir) .env(SCRIPTISTO_SOURCE_VAR, script_path); let working_directory = if cfg.build_in_script_dir { script_dir } else { script_cache_path }; common::run_command(working_directory, cmd, stderr_mode())?; } } } common::write_bytes( script_cache_path, &PathBuf::from("scriptisto.metadata"), String::new().as_bytes(), ) .context("Cannot write metadata file")?; Ok(()) } pub fn perform( build_mode: opt::BuildMode, script_path: &str, show_logs: bool, ) -> Result<(cfg::BuildSpec, PathBuf)> { let script_path = Path::new(script_path); let script_body = std::fs::read(script_path).context("Cannot read script file")?; let script_cache_path = common::build_cache_path(script_path).context(format!( "Cannot build cache path for script: {:?}", script_path ))?; debug!("Path: {:?}", script_path); debug!("Cache path: {:?}", script_cache_path); let cfg = cfg::BuildSpec::new(&script_body).context("Cannot parse build spec")?; let mut metadata_path = script_cache_path.clone(); metadata_path.push("scriptisto.metadata"); let metadata_modified = common::file_modified(&metadata_path).ok(); let script_modified = common::file_modified(script_path).ok(); // If source file is older than metadata file, also hash other paths. Those could be additional // inputs for the build, for example, which must be considered for triggering a rebuild. let mut additional_paths_max_modified: Option = None; if metadata_modified > script_modified { let full_script_path = script_path .canonicalize() .context("Cannot build full path from given script path")?; let script_dir = full_script_path .parent() .expect("script_src has no parent directory"); let mut num_additional_paths_scanned = 0; for additional_path in cfg.extra_src_paths.iter() { let mut full_additional_path = PathBuf::from(additional_path); if !full_additional_path.is_absolute() { full_additional_path = script_dir.join(additional_path); } debug!("Hashing additional path {:?}", full_additional_path); for entry_res in walkdir::WalkDir::new(&full_additional_path) .follow_links(true) .into_iter() { debug!("Checking directory entry {:?}", entry_res); if entry_res.is_err() { continue; } let entry = entry_res.as_ref().unwrap(); let metadata_res = entry.metadata(); if metadata_res.is_ok() && metadata_res.as_ref().unwrap().is_file() { num_additional_paths_scanned += 1; if num_additional_paths_scanned > 500000 { panic!("Too many files scanned"); } let modified_res = metadata_res.as_ref().unwrap().modified(); if modified_res.is_ok() && (additional_paths_max_modified.is_none() || *modified_res.as_ref().unwrap() > additional_paths_max_modified.unwrap()) { additional_paths_max_modified = Some(*modified_res.as_ref().unwrap()); if metadata_modified <= additional_paths_max_modified { debug!( "File {:?} is newer than metadata, causing rebuild", entry.path() ); break; } } else if modified_res.is_err() { debug!("Cannot get modification time of {:?}", entry.path()); } } } if metadata_modified <= additional_paths_max_modified { break; } } } let first_run = metadata_modified.is_none(); let skip_rebuild = metadata_modified > script_modified && metadata_modified > additional_paths_max_modified && build_mode == opt::BuildMode::Default; if skip_rebuild { debug!("Already compiled, skipping compilation"); } else { for file in cfg.files.iter() { common::write_bytes( &script_cache_path, &PathBuf::from(&file.path), file.content.as_bytes(), )?; } run_build_command( &cfg, &common::script_src_to_absolute(script_path)?, &script_cache_path, first_run, build_mode, || { if show_logs { Stdio::inherit() } else { Stdio::piped() } }, )?; } Ok((cfg, script_cache_path)) } scriptisto-2.2.0/src/cache.rs000064400000000000000000000074621046102023000142410ustar 00000000000000// Copyright 2019 The Scriptisto Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::opt::CacheCommand; use anyhow::{anyhow, Context, Result}; use number_prefix::NumberPrefix; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::process; use crate::*; fn print_item(name: &str, value: &str) { println!("{:20} {}", format!("{}:", name), value); } fn get_dir_size_lossy(path: &Path) -> String { let size: u64 = walkdir::WalkDir::new(path) .into_iter() .map(|r| { r.map(|e| e.metadata().map(|m| m.len()).unwrap_or_default()) .unwrap_or_default() }) .sum(); match NumberPrefix::binary(size as f64) { NumberPrefix::Standalone(bytes) => format!("{} bytes", bytes), NumberPrefix::Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix), } } fn collect_info(script_path: &Path) -> Result> { let script_body = std::fs::read(script_path).context("Cannot read script file")?; let script_cache_path = common::build_cache_path(script_path).context(format!( "Cannot build cache path for script: {:?}", script_path ))?; let cfg = cfg::BuildSpec::new(&script_body)?; let mut items = BTreeMap::new(); items.insert( "cache_path".into(), script_cache_path.to_string_lossy().to_string(), ); if cfg.docker_build.is_some() { items.insert( "docker_image".into(), build::docker_image_name(&script_cache_path)?, ); items.insert( "docker_src_volume".into(), build::docker_volume_name(&script_cache_path)?, ); items.insert("dir_size".into(), get_dir_size_lossy(&script_cache_path)); } Ok(items) } pub fn command_get(name: &str, script_path: &Path) -> Result<()> { let items = collect_info(script_path)?; if let Some(value) = items.get(name) { println!("{}", value); Ok(()) } else { Err(anyhow!( "'{}' is not found. Available items: {:?}.", name, items.keys() )) } } pub fn command_info(script_path: &Path) -> Result<()> { let items = collect_info(script_path)?; for (k, v) in items.iter() { print_item(k, v); } Ok(()) } pub fn command_clean(script_path: &Path) -> Result<()> { let items = collect_info(script_path)?; let cache_path = items.get("cache_path").expect("cache_path to exist"); let _ = std::fs::remove_dir_all(cache_path); if let Some(docker_image) = items.get("docker_image") { let mut cmd = process::Command::new("docker"); cmd.arg("image").arg("rm").arg(docker_image); let _ = common::run_command(&PathBuf::from("/"), cmd, process::Stdio::piped()); } if let Some(docker_volume) = items.get("docker_src_volume") { let mut cmd = process::Command::new("docker"); cmd.arg("volume").arg("rm").arg(docker_volume); let _ = common::run_command(&PathBuf::from("/"), cmd, process::Stdio::piped()); } Ok(()) } pub fn command_cache(cmd: CacheCommand) -> Result<()> { match cmd { CacheCommand::Clean { file } => command_clean(&file), CacheCommand::Get { name, file } => command_get(&name, &file), CacheCommand::Info { file } => command_info(&file), } } scriptisto-2.2.0/src/cfg.rs000064400000000000000000000071151046102023000137300ustar 00000000000000// Copyright 2019 The Scriptisto Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use anyhow::{Context, Result}; use log::debug; use serde_derive::Deserialize; use std::cmp::min; use std::io::{BufRead, BufReader}; #[derive(Deserialize, Debug)] pub struct BuildSpec { pub script_src: String, pub build_cmd: Option, pub build_once_cmd: Option, #[serde(default = "default_target_bin")] pub target_bin: String, pub target_interpreter: Option, #[serde(default)] pub replace_shebang_with: String, #[serde(default)] pub files: Vec, #[serde(default)] pub docker_build: Option, #[serde(default)] pub extra_src_paths: Vec, // paths to directory/file, no wildcards supported #[serde(default)] pub build_in_script_dir: bool, // use script directory as working directory of build, not the cache directory (non-Docker build only) } fn default_target_bin() -> String { "./script".into() } #[derive(Deserialize, Debug)] pub struct File { pub path: String, pub content: String, } #[derive(Deserialize, Debug)] pub struct DockerBuild { pub dockerfile: Option, pub src_mount_dir: Option, #[serde(default)] pub extra_args: Vec, } #[derive(Clone, Debug)] enum ParserState { ScriptSource, ConfigSource { prefix_len: usize }, } impl BuildSpec { pub fn new(script_body: &[u8]) -> Result { let mut script_src = Vec::new(); let reader = BufReader::new(script_body); use ParserState::*; let mut state = ParserState::ScriptSource; let mut cfg_src = vec![]; for (line_num, line) in reader.lines().enumerate() { let mut line = line.context(format!("Cannot parse script line: {}", line_num))?; script_src.push(line.clone()); state = match state { ScriptSource => { let sb_start = line.find("scriptisto-begin"); if let Some(pos) = sb_start { ConfigSource { prefix_len: pos } } else { state } } ConfigSource { prefix_len } => { line.drain(..min(prefix_len, line.len())); if line.starts_with("scriptisto-end") { ScriptSource } else { cfg_src.push(line); state } } }; } let mut build_spec: BuildSpec = serde_yaml::from_str(&cfg_src.join("\n")) .context(format!("Cannot parse config YAML: \n{:#?}", cfg_src))?; let replace_shebang_with = build_spec.replace_shebang_with.clone(); if !script_src.is_empty() { script_src[0] = replace_shebang_with; } build_spec.files.push(File { path: build_spec.script_src.clone(), content: script_src.join("\n"), }); debug!("BuildSpec parsed: {:#?}", build_spec); Ok(build_spec) } } scriptisto-2.2.0/src/common.rs000064400000000000000000000065331046102023000144640ustar 00000000000000// Copyright 2019 The Scriptisto Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use anyhow::{anyhow, Context, Result}; use log::debug; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; pub fn script_src_to_absolute(script_src: &Path) -> Result { let script_src_str = script_src.to_string_lossy(); if !script_src_str.starts_with(['.', '/']) { return Err(anyhow!( "Script path {:?} must start with '.' or '/'", script_src )); } Ok(script_src.canonicalize()?) } pub fn build_cache_path(script_path: &Path) -> Result { let script_path = script_src_to_absolute(script_path)?; let script_path_rel = script_path .strip_prefix("/") .context(format!("Could not strip '/' prefix from {:?}", script_path))?; let mut user_cache = dirs::cache_dir().ok_or_else(|| anyhow!("Cannot compute user's cache dir"))?; user_cache.push("scriptisto/bin"); user_cache.push(script_path_rel); Ok(user_cache) } pub fn write_bytes(cache_path: &Path, rel_path: &Path, data: &[u8]) -> Result<()> { let mut path = cache_path.to_path_buf(); path.push(rel_path); debug!("Writing {} bytes to {:?}", data.len(), path); let parent = path .parent() .ok_or_else(|| anyhow!("Cannot compute parent path of {:?}", path))?; std::fs::create_dir_all(parent).context(format!( "Cannot create cache directory for script, dir path: {:?}", parent ))?; let mut file = File::create(path).context("Cannot output extra file")?; file.write_all(data).context("Cannot write bytes to file")?; Ok(()) } pub fn file_modified(p: &Path) -> Result { let meta = std::fs::metadata(p)?; let modified = meta.modified()?; Ok(modified) } pub fn run_command( current_directory: &Path, mut cmd: Command, stderr_mode: Stdio, ) -> Result { cmd.stdout(Stdio::piped()) .stderr(stderr_mode) .current_dir(current_directory); debug!("Running command: {:?}", cmd); let out = cmd.output().context(format!( "Cannot run cmd={:?} in current_directory={:?}", cmd, current_directory ))?; let stderr = String::from_utf8_lossy(&out.stderr); let stdout = String::from_utf8_lossy(&out.stdout); debug!( "Command result: {:?}\nstderr:\n{}\nstdout:\n{}", out.status.code(), stderr, stdout ); if !out.status.success() { eprintln!("{}", stderr); eprintln!("{}", stdout); let error = match out.status.code() { Some(code) => anyhow!("Command {:?} failed. Exit code: {}.", cmd, code,), None => anyhow!("Child build process terminated by signal"), }; return Err(error); } Ok(out) } scriptisto-2.2.0/src/editor.rs000064400000000000000000000030001046102023000144440ustar 00000000000000use std::{ env, fs, path::{Path, PathBuf}, process::Command, }; use anyhow::Context; use crate::common; pub fn edit>(source_file_path: P, content: &str) -> anyhow::Result> { use std::env::var; let tmp_file = { let mut path = env::temp_dir(); path.push("scriptisto"); path.push(format!("{}", std::process::id())); if !path.exists() { fs::create_dir_all(&path).with_context(|| format!("Unable to make dir: {:?}", path))? } let mut filename = String::from("script"); if let Some(ext) = source_file_path.as_ref().extension() { filename.push('.'); filename.push_str(&ext.to_string_lossy()); } path.push(filename); path }; log::info!("{:?}", tmp_file); common::write_bytes(&PathBuf::from("/"), &tmp_file, content.as_bytes())?; let editors = [ var("VISUAL"), var("EDITOR"), Ok("vim".into()), Ok("vi".into()), ]; for editor in editors.iter().flatten() { if Command::new(editor).arg(tmp_file.clone()).status().is_ok() { let content_after_editor = fs::read_to_string(tmp_file)?; if content_after_editor == content { return Ok(None); } else { return Ok(Some(content_after_editor)); } } } Err(anyhow::anyhow!( "Unable to open editor, specify valid editor via EDITOR or VISUAL environment variables" )) } scriptisto-2.2.0/src/main.rs000064400000000000000000000114531046102023000141150ustar 00000000000000// Copyright 2019 The Scriptisto Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #[macro_use] extern crate include_dir; use anyhow::{anyhow, Context, Result}; use clap::Parser; use log::debug; use std::env; use std::path::{Path, PathBuf}; use std::process::exit; use std::str::FromStr; mod build; mod cache; mod cfg; mod common; mod editor; mod opt; mod templates; pub fn opt_from_args(args: &[String]) -> opt::Opt { let mut args_iter = args.iter(); args_iter.next(); if let Some(script_src) = args_iter.next() { let absolute_script_src = common::script_src_to_absolute(Path::new(&script_src)); if let Ok(absolute_script_src) = absolute_script_src { if absolute_script_src.exists() { let mut command: Vec = vec![absolute_script_src.to_string_lossy().into()]; command.append(&mut args_iter.cloned().collect()); return opt::Opt { command, cmd: None }; } } } let opts = opt::Opt::parse_from(args.iter()); debug!("Parsed command line options: {:#?}", opts); if opts.cmd.is_none() && opts.command.is_empty() { opt::display_help(); }; opts } fn default_main(script_path: &str, args: &[String]) -> Result<()> { let build_mode_env = std::env::var_os("SCRIPTISTO_BUILD").unwrap_or_default(); let build_mode = opt::BuildMode::from_str(&build_mode_env.to_string_lossy())?; let show_logs = std::env::var_os("SCRIPTISTO_BUILD_LOGS").is_some(); let (cfg, script_cache_path) = build::perform(build_mode, script_path, show_logs) .context(format!("Build failed for {:?}", script_path))?; let mut full_target_bin = script_cache_path.clone(); full_target_bin.push(PathBuf::from(cfg.target_bin)); let full_target_bin = full_target_bin .canonicalize()? .to_string_lossy() .to_string(); debug!("Full target_bin path: {:?}", full_target_bin); let (binary, mut target_argv) = match cfg.target_interpreter { Some(ref target_interpreter) if !target_interpreter.is_empty() => { let mut seq: Vec = target_interpreter .split_ascii_whitespace() .map(|s| s.to_string()) .collect(); let binary = seq .first() .expect("first() should work as we checked the guard above") .clone(); seq.drain(..1); seq.push(full_target_bin); (binary, seq) } _ => (full_target_bin, vec![]), }; target_argv.insert(0, binary.clone()); // args.drain(..2); target_argv.extend_from_slice(args); debug!("Running exec {:?}, Args: {:?}", binary, target_argv); // Scripts can use this to find other build artifacts env::set_var(build::SCRIPTISTO_CACHE_DIR_VAR, script_cache_path); let error = match exec::execvp(&binary, &target_argv) { exec::Error::Errno(e) => { anyhow!("Cannot execute target binary '{:?}': {:#?}", binary, e) } _ => anyhow!("Cannot exec"), }; Err(error) } fn main_err() -> Result<()> { let args: Vec = std::env::args().collect(); let opts = opt_from_args(&args); debug!("Parsed options: {:?}", opts); match opts.cmd { None => { let mut command_iter = opts.command.iter(); let script_src = command_iter.next().ok_or_else(|| { anyhow!("PROBABLY A BUG: script_src must be non-empty if no subcommand found.") })?; let script_src = common::script_src_to_absolute(Path::new(&script_src))?; let args: Vec = command_iter.cloned().collect(); default_main(&script_src.to_string_lossy(), args.as_slice()) } Some(opt::Command::Cache { cmd }) => cache::command_cache(cmd), Some(opt::Command::New { template_name }) => templates::command_new(template_name), Some(opt::Command::Template { cmd }) => templates::command_template(cmd), Some(opt::Command::Build { script_src, build_mode, }) => { let _ = build::perform(build_mode.unwrap_or_default(), &script_src, true); Ok(()) } } } fn main() { env_logger::init(); if let Err(e) = main_err() { eprintln!("Error: {:?}", e); exit(1); } } scriptisto-2.2.0/src/opt.rs000064400000000000000000000104401046102023000137660ustar 00000000000000// Copyright 2019 The Scriptisto Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use clap::{Parser, Subcommand}; use std::path::PathBuf; use std::str::FromStr; #[derive(Debug, Parser, PartialEq, Eq)] pub enum CacheCommand { /// Shows information about the cache directory for the script. Info { #[clap(help = "A filename of the script file.")] file: PathBuf, }, /// Clean the cache for a particular script. Removes the cache directory. Removes the Docker image/volume if /// they exist, but does not prune. #[clap(visible_alias = "clear")] Clean { #[clap(help = "A filename of the script file.")] file: PathBuf, }, /// Shows a particular item from "info" by name. Get { #[clap(help = "An item name, e.g. cache_path.")] name: String, #[clap(help = "A filename of the script file.")] file: PathBuf, }, } #[derive(Debug, Parser, PartialEq, Eq)] pub enum TemplatesCommand { /// Imports a template from file. Import { #[clap( help = "A filename of the script file. Extension will be stripped for the template name." )] file: PathBuf, }, /// Opens an editor to modify an existing template, nice for quick edits. Edit { #[clap(help = "A name of the template to edit")] template_name: String, }, /// Remove a custom template or reset it to the built-in contents. #[clap(name = "rm", visible_aliases = &["remove", "delete"])] Remove { #[clap(help = "A name of the template to remove")] template_name: String, }, /// List all templates. #[clap(name = "ls", visible_alias = "list")] List {}, } #[derive(Debug, PartialEq, Eq, Parser, Clone, Default)] #[clap(rename_all = "snake-case")] pub enum BuildMode { #[default] Default, Source, Full, } impl FromStr for BuildMode { type Err = anyhow::Error; fn from_str(s: &str) -> anyhow::Result { use BuildMode::*; Ok(match s { "" => Default, "source" => Source, "full" => Full, _ => { return Err(anyhow::anyhow!( "Incorrect build mode value. Available values: , source, full." )) } }) } } #[derive(Debug, Parser, PartialEq, Eq)] #[clap( name = "scriptisto", about = "A 'shebang-interpreter' for compiled languages", args_conflicts_with_subcommands = true )] pub struct Opt { /// A path for to a script to run and additional arguments passed to this script. A script path must start with '.' or '/'. #[clap(value_name = "SCRIPT")] pub command: Vec, #[clap(subcommand)] pub cmd: Option, } #[derive(Debug, PartialEq, Subcommand, Eq)] pub enum Command { /// Build cache operations. Cache { #[clap(subcommand)] cmd: CacheCommand, }, /// Prints an example starting script in a programming language of your /// choice. New { #[clap( help = "If specified, determines a language. Example usage: \"scriptisto new | tee new-script\".\nIf not specified, \"new\" lists available templates." )] template_name: Option, }, /// Manage custom script templates. Template { #[clap(subcommand)] cmd: TemplatesCommand, }, /// Build a script without running. Build { /// A path to a script to build. #[clap()] script_src: String, /// Build mode. If unset, only builds if necessary. "source" - to rebuild each time. "full" to fully re-fetch Docker image and run `build_once_cmd`. #[clap(short, long)] build_mode: Option, }, } pub fn display_help() { Opt::parse_from(vec!["", "help"]); } scriptisto-2.2.0/src/templates.rs000064400000000000000000000224761046102023000151760ustar 00000000000000// Copyright 2019 The Scriptisto Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::editor; use crate::opt::TemplatesCommand; use anyhow::{anyhow, Context, Result}; use include_dir::Dir; use log::debug; use std::collections::BTreeMap; use std::fmt::Debug; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; const TEMPLATES: Dir = include_dir!("./data/templates/"); #[derive(Debug, PartialEq, Eq)] enum Source { BuiltIn, Custom, } #[derive(Debug)] struct Template { source: Source, filename: String, contents: String, } type TemplateMap = BTreeMap; fn path_to_file_name + Debug>(p: T) -> Result { let p: PathBuf = p.as_ref().into(); Ok(p.file_name() .ok_or_else(|| anyhow!("Cannot extract filename from {:?}", p))? .to_string_lossy() .to_string()) } fn filename_to_template_name>(p: T) -> Result { let p: PathBuf = p.as_ref().into(); let file_name = path_to_file_name(&p)?; Ok(p.file_stem() .map(|f| f.to_string_lossy().to_string()) .unwrap_or(file_name)) } // Also creates the directory, this ok for now. fn filename_to_template_path + Debug>(p: T) -> Result { let file_name = path_to_file_name(&p)?; let templates_directory = get_templates_directory()?; std::fs::create_dir_all(&templates_directory)?; let mut template_path = templates_directory; template_path.push(file_name); Ok(template_path) } fn get_built_in_templates() -> Result { let mut templates = TemplateMap::new(); for file in TEMPLATES.files() { let path = PathBuf::from(file.path()); templates.insert( filename_to_template_name(&path)?, Template { source: Source::BuiltIn, filename: path_to_file_name(path)?, contents: file .contents_utf8() .ok_or_else(|| anyhow!("File {:?} is not UTF-8", file))? .to_string(), }, ); } Ok(templates) } fn get_templates_directory() -> Result { let mut p = dirs::config_dir().ok_or_else(|| anyhow!("Cannot compute user's config dir"))?; p.push("scriptisto/templates"); Ok(p) } fn get_custom_templates() -> Result { let mut templates = TemplateMap::new(); let templates_dir = get_templates_directory()?; debug!("Scanning for custom templates at {:?};", templates_dir); match std::fs::read_dir(&templates_dir) { Ok(dir_iter) => { debug!("Custom templates directory found"); for template_file in dir_iter { let template_file = template_file?; let name = filename_to_template_name(template_file.path())?; let filename = path_to_file_name(template_file.path())?; let contents = std::fs::read_to_string(template_file.path())?; templates.insert( name, Template { source: Source::Custom, filename, contents, }, ); } } Err(e) => { debug!("The custom templates directory skipped, reason: {:?}.", e); } } Ok(templates) } fn print_ascii_table(rows: &[Vec]) { use prettytable::{format, row, Cell, Row, Table}; let mut table = Table::new(); let format = format::FormatBuilder::new() .column_separator('|') .borders('|') .separators( &[format::LinePosition::Top, format::LinePosition::Bottom], format::LineSeparator::new('-', '+', '+', '+'), ) .separators( &[format::LinePosition::Title], format::LineSeparator::new('=', '+', '+', '+'), ) .padding(1, 1) .build(); table.set_format(format); table.set_titles(row!["Template Name", "Custom", "Extension"]); for table_row in rows { table.add_row(Row::new(table_row.iter().map(|s| Cell::new(s)).collect())); } table.printstd(); } fn get_templates() -> Result { let mut templates = get_built_in_templates()?; templates.append(&mut get_custom_templates()?); Ok(templates) } fn filename_extension(filename: &str) -> String { Path::new(filename) .extension() .map(|e| format!(".{}", e.to_string_lossy())) .unwrap_or_default() } fn print_templates(templates: &TemplateMap) { let table: Vec<_> = templates .iter() .map(|(k, v)| { vec![ k.clone(), match v.source { Source::BuiltIn => "", Source::Custom => "yes", } .to_string(), filename_extension(&v.filename), ] }) .collect(); print_ascii_table(&table); } fn template_not_found(name: &str, templates: &TemplateMap) -> ! { println!("Template '{}' is not found!", name); println!("Available templates in the table below:"); print_templates(templates); std::process::exit(1); } pub fn command_new(name: Option) -> Result<()> { let templates = get_templates()?; if let Some(name) = name { if let Some(template) = templates.get(&name) { println!("{}", template.contents); } else { template_not_found(&name, &templates); } } else { println!("Usage:\n$ scriptisto new