{"id":15502250,"url":"https://github.com/andrewtimberlake/trunk","last_synced_at":"2025-04-14T19:09:14.352Z","repository":{"id":38341109,"uuid":"94361975","full_name":"andrewtimberlake/trunk","owner":"andrewtimberlake","description":"📦 A file attachment/storage library for Elixir 📎","archived":false,"fork":false,"pushed_at":"2024-06-12T09:39:35.000Z","size":232,"stargazers_count":19,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-14T19:09:08.402Z","etag":null,"topics":["attachment","elixir","s3","s3-storage","storage","storage-library"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrewtimberlake.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-14T18:37:38.000Z","updated_at":"2025-04-14T08:24:07.000Z","dependencies_parsed_at":"2024-04-29T08:42:50.803Z","dependency_job_id":null,"html_url":"https://github.com/andrewtimberlake/trunk","commit_stats":{"total_commits":101,"total_committers":2,"mean_commits":50.5,"dds":0.00990099009900991,"last_synced_commit":"2ed035784733cf8fe39c94796001378849e226bc"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewtimberlake%2Ftrunk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewtimberlake%2Ftrunk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewtimberlake%2Ftrunk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewtimberlake%2Ftrunk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrewtimberlake","download_url":"https://codeload.github.com/andrewtimberlake/trunk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248943456,"owners_count":21186958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attachment","elixir","s3","s3-storage","storage","storage-library"],"created_at":"2024-10-02T09:08:58.908Z","updated_at":"2025-04-14T19:09:14.328Z","avatar_url":"https://github.com/andrewtimberlake.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Trunk\n\n[![Build Status](https://circleci.com/gh/andrewtimberlake/trunk.svg?style=shield)](https://circleci.com/gh/andrewtimberlake/trunk)\n[![Module Version](https://img.shields.io/hexpm/v/trunk.svg)](https://hex.pm/packages/trunk)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/trunk/)\n[![Total Download](https://img.shields.io/hexpm/dt/trunk.svg)](https://hex.pm/packages/trunk)\n[![License](https://img.shields.io/hexpm/l/trunk.svg)](https://github.com/andrewtimberlake/trunk/blob/master/LICENSE)\n[![Last Updated](https://img.shields.io/github/last-commit/andrewtimberlake/trunk.svg)](https://github.com/andrewtimberlake/trunk/commits/master)\n\nA file attachment/storage library for Elixir.\n\n## Installation\n\nAdd `:trunk` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:trunk, \"~\u003e 1.0\"},\n\n    # If you want to use Amazon S3, then add:\n    {:ex_aws_s3, \"~\u003e 2.0\"},\n    {:hackney,   \"~\u003e 1.7\"},\n    {:poison,    \"~\u003e 3.1\"},\n    {:sweet_xml, \"~\u003e 0.6\"},\n  ]\nend\n```\n\nTrunk has only one _hard_ dependency on [Briefly](https://hex.pm/packages/briefly) to handle temporary file creation (and auto-destruction)\n\n## Usage\n\nTrunk is a behaviour that is implemented in a module. `use Trunk` creates functions for storing, deleting, and generating urls for your files and their versions. It then implements callbacks in the simplest way possible. You can then override the callbacks you need to as you want to extend the behaviour.\n\n```elixir\ndefmodule MyTrunk do\n  use Trunk, versions: [:original, :thumb]\n\n  # override callbacks as needed.\nend\n```\n\n## Configuration\n\nTrunk has been designed to be highly configurable. It can be configured in stages with each level merging with the level before it.\n\nSee the [documentation](https://hexdocs.pm/trunk/Trunk.html#module-options) for all config options.\n\n### Global configuration\n\n```elixir\nconfig :trunk,\n  storage: Trunk.Storage.Filesystem,\n  storage_opts: [path: \"/tmp\"]\n```\n\n### App specific configuration for umbrella type configs\n\n```elixir\nconfig :my_app, :trunk,\n  storage: Trunk.Storage.S3,\n  storage_opts: [bucket: \"test-trunk\"]\n```\n\nin order for these options to be used, you need to pass the `otp_app` option when calling `use Trunk` as follows:\n\n```elixir\ndefmodule MyTrunk do\n  use Trunk, otp_app: :my_app\nend\n```\n\n### Module configuration\n\n```elixir\ndefmodule MyTrunk do\n  use Trunk, versions: [:original, :trunk],\n             storage: Trunk.Storage.Filesystem,\n             storage_opts: [path: \"/tmp\"]\nend\n```\n\n### Function options\n\n**Caution:** If you override options during the storage call, you need to be sure to pass the same options to other calls\n\n```elixir\nMyTrunk.store(\"/path/to/file.ext\", storage: Trunk.Storage.S3, storage_opts: [bucket: \"test-trunk\"])\n```\n\n## Storage\n\nStorage is handled by a behaviour.\n\nTwo storage handlers are included: [Trunk.Storage.Filesystem](https://hexdocs.pm/trunk/Trunk.Storage.Filesystem.html), and [Trunk.Storage.S3](https://hexdocs.pm/trunk/Trunk.Storage.S3.html)\nAdditional storage systems can be handled by creating a module that implements the [Trunk.Storage](https://hexdocs.pm/trunk/Trunk.Storage.html) behaviour.\n\nWhen storing files, Trunk runs the file through a transformation pipeline allowing you to generate different versions of a file.\nEach stage in the pipeline is handled via a callback allowing you to configure what transformations take place, where the version is stored and how it is named.\nFull information can be found [in the documentation](https://hexdocs.pm/trunk/Trunk.Storage.html#content)\n\n## Scope\n\nYou have the option of passing a scope (usually a struct or map) into the transform functions. This scope object will then be available in each callback allowing you to further customise the handling of each version.\n\n### Example:\n\n```elixir\ndefmodule MyTrunk do\n  use Trunk, versions: [:thumb]\n\n  def storage_dir(%Trunk.State{scope: %{id: model_id}}, :thumb)\n    do: \"my_models/#{model_id}\"\nend\n\nMyTrunk.store(\"/path/to/file.ext\", %{id: 42})\n# will save to \u003cstorage\u003e/my_models/42/\u003cfilename\u003e\n```\n\n## State\n\nState about the file and the version transformations is kept in a [Trunk.State](https://hexdocs.pm/trunk/Trunk.State.html) struct which is passed to each callback. Each version also keeps track of its own state in a [Trunk.VersionState](https://hexdocs.pm/trunk/Trunk.VersionState.html) struct which is also available through the `Trunk.State.versions` map.\n\n### Transformation\n\nOne of the key features of Trunk is the ability to take a file and produce transformed versions. Perhaps you want to take an uploaded photo and produce a thumbnail, take a video and extract thumbnails, or take an XLS file and produce a CSV file for easier processing.\nThis is all handled easily with the flexible version and transform system.\n\nSee full documentation on [Trunk.transform/2](https://hexdocs.pm/trunk/Trunk.html#c:transform/2)\n\n## Credits\n\nA shout out to [stavro](https://github.com/stavro) who created [arc](https://github.com/stavro/arc) which I used in many of my projects, and which provided much inspiration for what resulted in Trunk.\n\n### Photos used in testing\n\n- [coffee.jpg](https://unsplash.com/photos/Cdz_lvnl37k) by [Ronaldo Arthur Vidal](https://unsplash.com/@ronaldoav)\n- [coffee beans.jpg](http://unsplash.com/photos/JS-QXqSGVE8) by [Alex Jones](https://unsplash.com/@alexjones)\n\n## Copyright and License\n\nCopyright (c) 2017 Andrew Timberlake\n\nThis work is free. You can redistribute it and/or modify it under the\nterms of the MIT License. See the [LICENSE.md](./LICENSE.md) file for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewtimberlake%2Ftrunk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrewtimberlake%2Ftrunk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewtimberlake%2Ftrunk/lists"}