├── .gitattributes ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .nuget ├── NuGet.Config ├── NuGet.exe ├── NuGet.targets └── packages.config ├── .travis.yml ├── LICENSE.txt ├── README.md ├── RELEASE_NOTES.md ├── S3Provider.sln ├── build.cmd ├── build.fsx ├── build.sh ├── docs ├── content │ ├── index.fsx │ └── tutorial.fsx ├── files │ └── img │ │ ├── demo_screenshot.png │ │ └── logo.png └── tools │ ├── generate.fsx │ ├── packages.config │ └── templates │ └── template.cshtml ├── lib └── README.md ├── nuget ├── README.md ├── S3Provider.nuspec ├── logo.pdn ├── logo.png └── publish.cmd ├── src └── S3Provider │ ├── AssemblyInfo.fs │ ├── Model.fs │ ├── ProvidedTypes.fs │ ├── ProvidedTypes.fsi │ ├── Provider.fs │ ├── S3Provider.fsproj │ ├── Utils.fs │ ├── Utils.fsi │ └── packages.config └── tests └── S3Provider.Tests ├── Program.fs ├── S3Provider.Tests.fsproj └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Please provide a succinct description of your issue. 4 | 5 | ### Repro steps 6 | 7 | Please provide the steps required to reproduce the problem 8 | 9 | 1. Step A 10 | 11 | 2. Step B 12 | 13 | ### Expected behavior 14 | 15 | Please provide a description of the behavior you expect. 16 | 17 | ### Actual behavior 18 | 19 | Please provide a description of the actual behavior you observe. 20 | 21 | ### Known workarounds 22 | 23 | Please provide a description of any known workarounds. 24 | 25 | ### Related information 26 | 27 | * Operating system 28 | * Branch 29 | * .NET Runtime, CoreCLR or Mono Version 30 | * Performance information, links to performance testing scripts 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # Enable nuget.exe in the .nuget folder (though normally executables are not tracked) 99 | !.nuget/NuGet.exe 100 | 101 | # Windows Azure Build Output 102 | csx 103 | *.build.csdef 104 | 105 | # Windows Store app package directory 106 | AppPackages/ 107 | 108 | # Others 109 | sql/ 110 | *.Cache 111 | ClientBin/ 112 | [Ss]tyle[Cc]op.* 113 | ~$* 114 | *~ 115 | *.dbmdl 116 | *.[Pp]ublish.xml 117 | *.pfx 118 | *.publishsettings 119 | 120 | # RIA/Silverlight projects 121 | Generated_Code/ 122 | 123 | # Backup & report files from converting an old project file to a newer 124 | # Visual Studio version. Backup files are not needed, because we have git ;-) 125 | _UpgradeReport_Files/ 126 | Backup*/ 127 | UpgradeLog*.XML 128 | UpgradeLog*.htm 129 | 130 | # SQL Server files 131 | App_Data/*.mdf 132 | App_Data/*.ldf 133 | 134 | 135 | #LightSwitch generated files 136 | GeneratedArtifacts/ 137 | _Pvt_Extensions/ 138 | ModelManifest.xml 139 | 140 | # ========================= 141 | # Windows detritus 142 | # ========================= 143 | 144 | # Windows image file caches 145 | Thumbs.db 146 | ehthumbs.db 147 | 148 | # Folder config file 149 | Desktop.ini 150 | 151 | # Recycle Bin used on file shares 152 | $RECYCLE.BIN/ 153 | 154 | # Mac desktop service store files 155 | .DS_Store 156 | 157 | # =================================================== 158 | # Exclude F# project specific directories and files 159 | # =================================================== 160 | 161 | # NuGet Packages Directory 162 | packages/ 163 | 164 | # Generated documentation folder 165 | docs/output/ 166 | 167 | # Temp folder used for publishing docs 168 | temp/ 169 | 170 | # Test results produced by build 171 | TestResults.xml 172 | -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/S3Provider/082a26f9584b0053778091348e7ef40219c35fff/.nuget/NuGet.exe -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) 32 | 33 | 34 | 35 | 36 | $(SolutionDir).nuget 37 | packages.config 38 | 39 | 40 | 41 | 42 | $(NuGetToolsPath)\NuGet.exe 43 | @(PackageSource) 44 | 45 | "$(NuGetExePath)" 46 | mono --runtime=v4.0.30319 $(NuGetExePath) 47 | 48 | $(TargetDir.Trim('\\')) 49 | 50 | -RequireConsent 51 | -NonInteractive 52 | 53 | "$(SolutionDir) " 54 | "$(SolutionDir)" 55 | 56 | 57 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 58 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 59 | 60 | 61 | 62 | RestorePackages; 63 | $(BuildDependsOn); 64 | 65 | 66 | 67 | 68 | $(BuildDependsOn); 69 | BuildPackage; 70 | 71 | 72 | 73 | 74 | 75 | 76 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | 98 | 100 | 101 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /.nuget/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | 3 | env: 4 | matrix: 5 | - MONO_VERSION="3.4.0" 6 | 7 | install: 8 | - wget "http://download.mono-project.com/archive/${MONO_VERSION}/macos-10-x86/MonoFramework-MDK-${MONO_VERSION}.macos10.xamarin.x86.pkg" 9 | - sudo installer -pkg "MonoFramework-MDK-${MONO_VERSION}.macos10.xamarin.x86.pkg" -target / 10 | 11 | script: 12 | - ./build.sh 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Yan Cui 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Issue Stats](http://issuestats.com/github/fsprojects/S3Provider/badge/issue)](http://issuestats.com/github/fsprojects/S3Provider) 2 | [![Issue Stats](http://issuestats.com/github/fsprojects/S3Provider/badge/pr)](http://issuestats.com/github/fsprojects/S3Provider) 3 | 4 | S3 Type Provider [![NuGet Status](http://img.shields.io/nuget/v/S3Provider.svg?style=flat)](https://www.nuget.org/packages/S3Provider/) 5 | ======================= 6 | 7 | A F# type provider for **Amazon S3**. 8 | 9 | ### Example 10 | 11 | ```fsharp 12 | 13 | // create a type representing the S3 account with the specified AWS credentials 14 | type S3 = S3Provider.Account<"AWS Key", "AWS Secret"> 15 | 16 | // then access meta-data and content of objects in S3 with full intellisense support! 17 | 18 | // immediately after the type representing the account are all the buckets 19 | type bucket = S3.``my.bucket`` 20 | 21 | // you can then select folders/files from that bucket 22 | type folder = bucket.``2013-12-13/`` 23 | 24 | // on files, you can get meta-data such as ETag, LastModified, or fetch the content as 25 | // * Raw - raw binary array 26 | // * UTF8 - the content as decoded using UTF8 27 | // * ASCII - the content as decoded using ASCII 28 | let etag = folder.``My file.txt``.ETag 29 | let utf8 = folder.``My file.txt``.Content.UTF8 30 | let raw = folder.``My image.png``.Content.Raw 31 | let lastModified = folder.``My image.png``.LastModified 32 | 33 | // if the bucket/folder is large, you can also use the `Search<...>` generic type to find 34 | // files in the bucket by prefix 35 | type search = bucket.Search<"2013-12-"> 36 | 37 | // you can then navigate through the search results the same as before! 38 | let searchResultContent = search.``2013-12-13``.``My file.txt``.Content.Raw 39 | ``` 40 | 41 | ### Demo Video 42 | 43 | [![ScreenShot](https://raw.github.com/theburningmonk/S3Provider/develop/docs/files/img/demo_screenshot.png)](http://www.youtube.com/watch?v=LOU00RlArqg) 44 | 45 | ### Maintainer(s) 46 | 47 | - [@theburningmonk](https://github.com/theburningmonk) 48 | 49 | The default maintainer account for projects under "fsprojects" is [@fsprojectsgit](https://github.com/fsprojectsgit) - F# Community Project Incubation Space (repo management) 50 | -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | #### 0.0.1 - December 14 2013 2 | * Initial release 3 | 4 | #### 0.0.2 - December 16 2013 5 | * Support versioned buckets and show all versions of a S3 object 6 | * Support folder structures inside a bucket 7 | * Support the use of generic `Search` types on buckets which filters keys by supplied prefix 8 | * Object type names no longer has the prefix of parent folders 9 | * For large buckets, don't load everything, but push user to use the `Search` type instead 10 | * `S3Provider.SimpleStorageService` is renamed to `S3Provider.Account` 11 | * Top level module `Provider` is made into a namespace and renamed to `AwsProviders` 12 | 13 | #### 0.0.3 - December 17 2013 14 | * Versions of a S3 object is sorted chronologically 15 | 16 | #### 0.0.4 - December 18 2013 17 | * Removed dependency on AWSSDK 18 | * Fixed bug with getting data for versioned S3 object 19 | 20 | #### 0.0.5 - December 18 2013 21 | * Fixed bug with accessing the `CreationDate` on bucket types -------------------------------------------------------------------------------- /S3Provider.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1F1B4F0F-2998-4D74-865B-9122611C2B14}" 5 | ProjectSection(SolutionItems) = preProject 6 | .nuget\NuGet.Config = .nuget\NuGet.Config 7 | .nuget\NuGet.exe = .nuget\NuGet.exe 8 | .nuget\NuGet.targets = .nuget\NuGet.targets 9 | EndProjectSection 10 | EndProject 11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}" 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{BF60BC93-E09B-4E5F-9D85-95A519479D54}" 14 | ProjectSection(SolutionItems) = preProject 15 | build.fsx = build.fsx 16 | README.md = README.md 17 | RELEASE_NOTES.md = RELEASE_NOTES.md 18 | nuget\S3Provider.nuspec = nuget\S3Provider.nuspec 19 | EndProjectSection 20 | EndProject 21 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{83F16175-43B1-4C90-A1EE-8E351C33435D}" 22 | ProjectSection(SolutionItems) = preProject 23 | docs\tools\generate.fsx = docs\tools\generate.fsx 24 | docs\tools\templates\template.cshtml = docs\tools\templates\template.cshtml 25 | EndProjectSection 26 | EndProject 27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{8E6D5255-776D-4B61-85F9-73C37AA1FB9A}" 28 | ProjectSection(SolutionItems) = preProject 29 | docs\content\index.fsx = docs\content\index.fsx 30 | docs\content\tutorial.fsx = docs\content\tutorial.fsx 31 | EndProjectSection 32 | EndProject 33 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{ED8079DD-2B06-4030-9F0F-DC548F98E1C4}" 34 | EndProject 35 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "S3Provider", "src\S3Provider\S3Provider.fsproj", "{7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}" 36 | EndProject 37 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "S3Provider.Tests", "tests\S3Provider.Tests\S3Provider.Tests.fsproj", "{E789C72A-5CFD-436B-8EF1-61AA2852A89F}" 38 | EndProject 39 | Global 40 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 41 | Debug|Any CPU = Debug|Any CPU 42 | Release|Any CPU = Release|Any CPU 43 | EndGlobalSection 44 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 45 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F}.Release|Any CPU.Build.0 = Release|Any CPU 53 | EndGlobalSection 54 | GlobalSection(SolutionProperties) = preSolution 55 | HideSolutionNode = FALSE 56 | EndGlobalSection 57 | GlobalSection(NestedProjects) = preSolution 58 | {83F16175-43B1-4C90-A1EE-8E351C33435D} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1} 59 | {8E6D5255-776D-4B61-85F9-73C37AA1FB9A} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1} 60 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F} = {ED8079DD-2B06-4030-9F0F-DC548F98E1C4} 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | cls 3 | if not exist packages\FAKE\tools\Fake.exe ( 4 | .nuget\nuget.exe install FAKE -OutputDirectory packages -ExcludeVersion 5 | ) 6 | packages\FAKE\tools\FAKE.exe build.fsx %* 7 | pause 8 | -------------------------------------------------------------------------------- /build.fsx: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------- 2 | // FAKE build script 3 | // -------------------------------------------------------------------------------------- 4 | 5 | #r @"packages/FAKE/tools/FakeLib.dll" 6 | open Fake 7 | open Fake.Git 8 | open Fake.AssemblyInfoFile 9 | open Fake.ReleaseNotesHelper 10 | open System 11 | 12 | // -------------------------------------------------------------------------------------- 13 | // START TODO: Provide project-specific details below 14 | // -------------------------------------------------------------------------------------- 15 | 16 | // Information about the project are used 17 | // - for version and project name in generated AssemblyInfo file 18 | // - by the generated NuGet package 19 | // - to run tests and to publish documentation on GitHub gh-pages 20 | // - for documentation, you also need to edit info in "docs/tools/generate.fsx" 21 | 22 | // The name of the project 23 | // (used by attributes in AssemblyInfo, name of a NuGet package and directory in 'src') 24 | let project = "S3Provider" 25 | 26 | // Short summary of the project 27 | // (used as description in AssemblyInfo and as a short summary for NuGet package) 28 | let summary = "F# type provider for Amazon S3" 29 | 30 | // Longer description of the project 31 | // (used as a description for NuGet package; line breaks are automatically cleaned up) 32 | let description = """ 33 | This library is for the .Net platform implementating a type provider for Amazon S3.""" 34 | // List of author names (for NuGet package) 35 | let authors = [ "Yan Cui" ] 36 | // Tags for your project (for NuGet package) 37 | let tags = "F# fsharp aws s3 amazon cloud" 38 | 39 | // File system information 40 | // (.sln is built during the building process) 41 | let solutionFile = "S3Provider" 42 | // Pattern specifying assemblies to be tested using NUnit 43 | let testAssemblies = ["tests/*/bin/*/S3Provider*Tests*.dll"] 44 | 45 | // Git configuration (used for publishing documentation in gh-pages branch) 46 | // The profile where the project is posted 47 | let gitHome = "https://github.com/theburningmonk" 48 | // The name of the project on GitHub 49 | let gitName = "S3Provider" 50 | 51 | // -------------------------------------------------------------------------------------- 52 | // END TODO: The rest of the file includes standard build steps 53 | // -------------------------------------------------------------------------------------- 54 | 55 | // Read additional information from the release notes document 56 | Environment.CurrentDirectory <- __SOURCE_DIRECTORY__ 57 | let release = parseReleaseNotes (IO.File.ReadAllLines "RELEASE_NOTES.md") 58 | 59 | // Generate assembly info files with the right version & up-to-date information 60 | Target "AssemblyInfo" (fun _ -> 61 | let fileName = "src/" + project + "/AssemblyInfo.fs" 62 | CreateFSharpAssemblyInfo fileName 63 | [ Attribute.Title project 64 | Attribute.Product project 65 | Attribute.Description summary 66 | Attribute.Version release.AssemblyVersion 67 | Attribute.FileVersion release.AssemblyVersion ] 68 | ) 69 | 70 | // -------------------------------------------------------------------------------------- 71 | // Clean build results & restore NuGet packages 72 | 73 | Target "RestorePackages" RestorePackages 74 | 75 | Target "Clean" (fun _ -> 76 | CleanDirs ["bin"; "temp"] 77 | ) 78 | 79 | Target "CleanDocs" (fun _ -> 80 | CleanDirs ["docs/output"] 81 | ) 82 | 83 | // -------------------------------------------------------------------------------------- 84 | // Build library & test project 85 | 86 | Target "Build" (fun _ -> 87 | { BaseDirectory = __SOURCE_DIRECTORY__ 88 | Includes = [ solutionFile + ".sln" 89 | solutionFile + ".Tests.sln" ] 90 | Excludes = [] } 91 | |> MSBuildRelease "" "Rebuild" 92 | |> ignore 93 | ) 94 | 95 | // -------------------------------------------------------------------------------------- 96 | // Run the unit tests using test runner & kill test runner when complete 97 | 98 | Target "RunTests" (fun _ -> 99 | let result = 100 | ExecProcess (fun info -> 101 | info.FileName <- "tests/S3Provider.Tests/bin/Debug/S3Provider.Tests.exe" 102 | ) (System.TimeSpan.FromSeconds(30.)) 103 | 104 | match result with 105 | | 0 -> () 106 | | _ -> failwith "Unit-tests failed." 107 | ) 108 | 109 | FinalTarget "CloseTestRunner" (fun _ -> 110 | ProcessHelper.killProcess "nunit-agent.exe" 111 | ) 112 | 113 | // -------------------------------------------------------------------------------------- 114 | // Build a NuGet package 115 | 116 | Target "NuGet" (fun _ -> 117 | // Format the description to fit on a single line (remove \r\n and double-spaces) 118 | let description = description.Replace("\r", "") 119 | .Replace("\n", "") 120 | .Replace(" ", " ") 121 | 122 | NuGet (fun p -> 123 | { p with 124 | Authors = authors 125 | Project = project 126 | Summary = summary 127 | Description = description 128 | Version = release.NugetVersion 129 | ReleaseNotes = String.Join(Environment.NewLine, release.Notes) 130 | Tags = tags 131 | OutputPath = "bin" 132 | AccessKey = getBuildParamOrDefault "nugetkey" "" 133 | Publish = hasBuildParam "nugetkey" 134 | Dependencies = [] }) 135 | ("nuget/" + project + ".nuspec") 136 | ) 137 | 138 | // -------------------------------------------------------------------------------------- 139 | // Generate the documentation 140 | 141 | Target "GenerateDocs" (fun _ -> 142 | executeFSIWithArgs "docs/tools" "generate.fsx" ["--define:RELEASE"] [] |> ignore 143 | ) 144 | 145 | // -------------------------------------------------------------------------------------- 146 | // Release Scripts 147 | 148 | Target "ReleaseDocs" (fun _ -> 149 | let ghPages = "gh-pages" 150 | let ghPagesLocal = "temp/gh-pages" 151 | Repository.clone "temp" (gitHome + "/" + gitName + ".git") ghPages 152 | Branches.checkoutBranch ghPagesLocal ghPages 153 | fullclean ghPagesLocal 154 | CopyRecursive "docs/output" ghPagesLocal true |> printfn "%A" 155 | CommandHelper.runSimpleGitCommand ghPagesLocal "add ." |> printfn "%s" 156 | let cmd = sprintf """commit -a -m "Update generated documentation for version %s""" release.NugetVersion 157 | CommandHelper.runSimpleGitCommand ghPagesLocal cmd |> printfn "%s" 158 | Branches.push ghPagesLocal 159 | ) 160 | 161 | Target "Release" DoNothing 162 | 163 | // -------------------------------------------------------------------------------------- 164 | // Run all targets by default. Invoke 'build ' to override 165 | 166 | Target "All" DoNothing 167 | 168 | "Clean" 169 | ==> "RestorePackages" 170 | ==> "AssemblyInfo" 171 | ==> "Build" 172 | ==> "RunTests" 173 | ==> "All" 174 | 175 | "All" 176 | ==> "CleanDocs" 177 | // ==> "GenerateDocs" 178 | // ==> "ReleaseDocs" 179 | ==> "NuGet" 180 | ==> "Release" 181 | 182 | RunTargetOrDefault "All" 183 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ ! -f packages/FAKE/tools/Fake.exe ]; then 5 | mono .NuGet/NuGet.exe install FAKE -OutputDirectory packages -ExcludeVersion 6 | fi 7 | mono packages/FAKE/tools/FAKE.exe build.fsx $@ 8 | -------------------------------------------------------------------------------- /docs/content/index.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | // This block of code is omitted in the generated HTML documentation. Use 3 | // it to define helpers that you do not want to show in the documentation. 4 | #I "../../bin" 5 | 6 | (** 7 | S3 Provider 8 | =================== 9 | 10 | Documentation 11 | 12 |
13 |
14 |
15 |
16 | The S3Provider library can be installed from NuGet: 17 |
PM> Install-Package S3Provider
18 |
19 |
20 |
21 |
22 | 23 | S3 Provider 24 | 25 | Example 26 | ------- 27 | 28 | This example demonstrates using a function defined in this sample library. 29 | 30 | *) 31 | #r "S3Provider.dll" 32 | #r "AWSSDK.dll" 33 | 34 | (** 35 | Some more info 36 | 37 | Samples & documentation 38 | ----------------------- 39 | 40 | The library comes with comprehensible documentation. 41 | It can include a tutorials automatically generated from `*.fsx` files in [the content folder][content]. 42 | The API reference is automatically generated from Markdown comments in the library implementation. 43 | 44 | * [Tutorial](tutorial.html) contains a further explanation of this sample library. 45 | 46 | * [API Reference](reference/index.html) contains automatically generated documentation for all types, modules 47 | and functions in the library. This includes additional brief samples on using most of the 48 | functions. 49 | 50 | Contributing and copyright 51 | -------------------------- 52 | 53 | The project is hosted on [GitHub][gh] where you can [report issues][issues], fork 54 | the project and submit pull requests. If you're adding new public API, please also 55 | consider adding [samples][content] that can be turned into a documentation. You might 56 | also want to read [library design notes][readme] to understand how it works. 57 | 58 | The library is available under Public Domain license, which allows modification and 59 | redistribution for both commercial and non-commercial purposes. For more information see the 60 | [License file][license] in the GitHub repository. 61 | 62 | [content]: https://github.com/theburningmonk/S3Provider/tree/master/docs/content 63 | [gh]: https://github.com/theburningmonk/S3Provider 64 | [issues]: https://github.com/theburningmonk/S3Provider/issues 65 | [readme]: https://github.com/theburningmonk/S3Provider/blob/master/README.md 66 | [license]: https://github.com/theburningmonk/S3Provider/blob/master/LICENSE.txt 67 | *) 68 | -------------------------------------------------------------------------------- /docs/content/tutorial.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | // This block of code is omitted in the generated HTML documentation. Use 3 | // it to define helpers that you do not want to show in the documentation. 4 | #I "../../bin" 5 | 6 | (** 7 | Introducing your project 8 | ======================== 9 | 10 | Say more 11 | 12 | *) 13 | #r "S3Provider.dll" 14 | #r "AWSSDK.dll" 15 | 16 | (** 17 | Coming soon 18 | *) 19 | -------------------------------------------------------------------------------- /docs/files/img/demo_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/S3Provider/082a26f9584b0053778091348e7ef40219c35fff/docs/files/img/demo_screenshot.png -------------------------------------------------------------------------------- /docs/files/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/S3Provider/082a26f9584b0053778091348e7ef40219c35fff/docs/files/img/logo.png -------------------------------------------------------------------------------- /docs/tools/generate.fsx: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------- 2 | // Builds the documentation from `.fsx` and `.md` files in the 'docs/content' directory 3 | // (the generated documentation is stored in the 'docs/output' directory) 4 | // -------------------------------------------------------------------------------------- 5 | 6 | // Binaries that have XML documentation (in a corresponding generated XML file) 7 | let referenceBinaries = [ "S3Provider.dll" ] 8 | // Web site location for the generated documentation 9 | let website = "/S3Provider" 10 | 11 | // Specify more information about your project 12 | let info = 13 | [ "project-name", "S3Provider" 14 | "project-author", "Yan Cui" 15 | "project-summary", "A F# type provider for Amazon S3" 16 | "project-github", "http://github.com/theburningmonk/S3Provider" 17 | "project-nuget", "http://nuget.org/packages/S3Provider" ] 18 | 19 | // -------------------------------------------------------------------------------------- 20 | // For typical project, no changes are needed below 21 | // -------------------------------------------------------------------------------------- 22 | 23 | #I "../../packages/FSharp.Formatting.2.1.6/lib/net40" 24 | #I "../../packages/RazorEngine.3.3.0/lib/net40/" 25 | #r "../../packages/Microsoft.AspNet.Razor.2.0.30506.0/lib/net40/System.Web.Razor.dll" 26 | #r "../../packages/FAKE/tools/FakeLib.dll" 27 | #r "RazorEngine.dll" 28 | #r "FSharp.Literate.dll" 29 | #r "FSharp.CodeFormat.dll" 30 | #r "FSharp.MetadataFormat.dll" 31 | open Fake 32 | open System.IO 33 | open Fake.FileHelper 34 | open FSharp.Literate 35 | open FSharp.MetadataFormat 36 | 37 | // When called from 'build.fsx', use the public project URL as 38 | // otherwise, use the current 'output' directory. 39 | #if RELEASE 40 | let root = website 41 | #else 42 | let root = "file://" + (__SOURCE_DIRECTORY__ @@ "../output") 43 | #endif 44 | 45 | // Paths with template/source/output locations 46 | let bin = __SOURCE_DIRECTORY__ @@ "../../bin" 47 | let content = __SOURCE_DIRECTORY__ @@ "../content" 48 | let output = __SOURCE_DIRECTORY__ @@ "../output" 49 | let files = __SOURCE_DIRECTORY__ @@ "../files" 50 | let templates = __SOURCE_DIRECTORY__ @@ "templates" 51 | let formatting = __SOURCE_DIRECTORY__ @@ "../../packages/FSharp.Formatting.2.1.6/" 52 | let docTemplate = formatting @@ "templates/docpage.cshtml" 53 | 54 | // Where to look for *.csproj templates (in this order) 55 | let layoutRoots = 56 | [ templates; formatting @@ "templates" 57 | formatting @@ "templates/reference" ] 58 | 59 | // Copy static files and CSS + JS from F# Formatting 60 | let copyFiles () = 61 | CopyRecursive files output true |> Log "Copying file: " 62 | ensureDirectory (output @@ "content") 63 | CopyRecursive (formatting @@ "content") (output @@ "content") true 64 | |> Log "Copying styles and scripts: " 65 | 66 | // Build API reference from XML comments 67 | let buildReference () = 68 | CleanDir (output @@ "reference") 69 | for lib in referenceBinaries do 70 | MetadataFormat.Generate 71 | ( bin @@ lib, output @@ "reference", layoutRoots, 72 | parameters = ("root", root)::info ) 73 | 74 | // Build documentation from `fsx` and `md` files in `docs/content` 75 | let buildDocumentation () = 76 | let subdirs = Directory.EnumerateDirectories(content, "*", SearchOption.AllDirectories) 77 | for dir in Seq.append [content] subdirs do 78 | let sub = if dir.Length > content.Length then dir.Substring(content.Length + 1) else "." 79 | Literate.ProcessDirectory 80 | ( dir, docTemplate, output @@ sub, replacements = ("root", root)::info, 81 | layoutRoots = layoutRoots ) 82 | 83 | // Generate 84 | copyFiles() 85 | buildDocumentation() 86 | buildReference() -------------------------------------------------------------------------------- /docs/tools/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/tools/templates/template.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 |
24 |
25 | 29 |

@Properties["project-name"]

30 |
31 |
32 |
33 |
34 | @RenderBody() 35 |
36 |
37 | 52 |
53 |
54 |
55 | Fork me on GitHub 56 | 57 | 58 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | This file is in the `lib` directory. 2 | 3 | Any **libraries** on which your project depends and which are **NOT managed via NuGet** should be kept **in this directory**. 4 | This typically includes custom builds of third-party software, private (i.e. to a company) codebases, and native libraries. 5 | 6 | --- 7 | NOTE: 8 | 9 | This file is a placeholder, used to preserve directory structure in Git. 10 | 11 | This file does not need to be edited. 12 | -------------------------------------------------------------------------------- /nuget/README.md: -------------------------------------------------------------------------------- 1 | This file is in the `nuget` directory. 2 | 3 | You should use this directory to store any artifacts required to produce a NuGet package for your project. 4 | This typically includes a `.nuspec` file and some `.ps1` scripts, for instance. 5 | Additionally, this example project includes a `.cmd` file suitable for manual deployment of packages to http://nuget.org. 6 | 7 | --- 8 | NOTE: 9 | 10 | This file is a placeholder, used to preserve directory structure in Git. 11 | 12 | This file does not need to be edited. 13 | -------------------------------------------------------------------------------- /nuget/S3Provider.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @project@ 5 | @build.number@ 6 | @authors@ 7 | @authors@ 8 | http://github.com/theburningmonk/S3Provider/blob/master/LICENSE.txt 9 | http://github.com/theburningmonk/S3Provider 10 | https://raw.github.com/theburningmonk/S3Provider/master/nuget/logo.png 11 | false 12 | @summary@ 13 | @description@ 14 | @releaseNotes@ 15 | Copyright 2013 16 | @tags@ 17 | @dependencies@ 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /nuget/logo.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/S3Provider/082a26f9584b0053778091348e7ef40219c35fff/nuget/logo.pdn -------------------------------------------------------------------------------- /nuget/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/S3Provider/082a26f9584b0053778091348e7ef40219c35fff/nuget/logo.png -------------------------------------------------------------------------------- /nuget/publish.cmd: -------------------------------------------------------------------------------- 1 | @for %%f in (..\bin\*.nupkg) do @..\.nuget\NuGet.exe push %%f -------------------------------------------------------------------------------- /src/S3Provider/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | namespace System 2 | open System.Reflection 3 | 4 | [] 5 | [] 6 | [] 7 | [] 8 | [] 9 | do () 10 | 11 | module internal AssemblyVersionInformation = 12 | let [] Version = "0.0.5" 13 | -------------------------------------------------------------------------------- /src/S3Provider/Model.fs: -------------------------------------------------------------------------------- 1 | namespace AwsProvider.S3.Model 2 | 3 | open System 4 | open System.Xml.Serialization 5 | 6 | type AwsCredential = { AwsKey : string; AwsSecret : string } 7 | 8 | [] 9 | [] 10 | type Owner = 11 | { 12 | [] 13 | Id : string 14 | [] 15 | DisplayName : string 16 | } 17 | 18 | [] 19 | [] 20 | type Bucket = 21 | { 22 | [] 23 | Name : string 24 | [] 25 | CreationDate : DateTime 26 | } 27 | 28 | [] 29 | [] 30 | type CommonPrefixes = 31 | { 32 | [] 33 | Prefix : string 34 | } 35 | 36 | type IS3Object = 37 | abstract member Key : string 38 | abstract member LastModified : DateTime 39 | abstract member ETag : string 40 | abstract member Size : uint64 41 | abstract member Owner : Owner 42 | abstract member StorageClass : string 43 | 44 | type IS3ObjectVersion = 45 | inherit IS3Object 46 | abstract member VersionId : string 47 | abstract member IsLatest : bool 48 | 49 | [] 50 | [] 51 | type S3Object = 52 | { 53 | [] 54 | Key : string 55 | [] 56 | LastModified : DateTime 57 | [] 58 | ETag : string 59 | [] 60 | Size : uint64 61 | [] 62 | Owner : Owner 63 | [] 64 | StorageClass : string 65 | } 66 | 67 | interface IS3Object with 68 | member this.Key = this.Key 69 | member this.LastModified = this.LastModified 70 | member this.ETag = this.ETag 71 | member this.Size = this.Size 72 | member this.Owner = this.Owner 73 | member this.StorageClass = this.StorageClass 74 | 75 | [] 76 | [] 77 | type S3ObjectVersion = 78 | { 79 | [] 80 | Key : string 81 | [] 82 | VersionId : string 83 | [] 84 | IsLatest : bool 85 | [] 86 | LastModified : DateTime 87 | [] 88 | ETag : string 89 | [] 90 | Size : uint64 91 | [] 92 | Owner : Owner 93 | [] 94 | StorageClass : string 95 | } 96 | 97 | interface IS3ObjectVersion with 98 | member this.Key = this.Key 99 | member this.LastModified = this.LastModified 100 | member this.ETag = this.ETag 101 | member this.Size = this.Size 102 | member this.Owner = this.Owner 103 | member this.StorageClass = this.StorageClass 104 | member this.VersionId = this.VersionId 105 | member this.IsLatest = this.IsLatest 106 | 107 | [] 108 | [] 109 | type ListAllMyBucketsResult = 110 | { 111 | [] 112 | Owner : Owner 113 | [] 114 | [, ElementName = "Bucket")>] 115 | Buckets : Bucket[] 116 | } 117 | 118 | [] 119 | [] 120 | type VersioningConfiguration = 121 | { 122 | [] 123 | Status : string 124 | [] 125 | MfaDelete : string 126 | } 127 | 128 | [] 129 | [] 130 | type ListBucketResult = 131 | { 132 | [] 133 | Name : string 134 | [] 135 | Prefix : string 136 | [] 137 | Marker : string 138 | [] 139 | NextMarker : string 140 | [] 141 | MaxKeys : int 142 | [] 143 | Delimiter : string 144 | [] 145 | IsTruncated : bool 146 | [] 147 | S3Objects : S3Object[] 148 | [] 149 | CommonPrefixes : CommonPrefixes[] 150 | } 151 | 152 | [] 153 | [] 154 | type ListVersionsResult = 155 | { 156 | [] 157 | Name : string 158 | [] 159 | Prefix : string 160 | [] 161 | Marker : string 162 | [] 163 | VersionIdMarker : string 164 | [] 165 | NextKeyMarker : string 166 | [] 167 | NextVersionIdMarker : string 168 | [] 169 | MaxKeys : int 170 | [] 171 | Delimiter : string 172 | [] 173 | IsTruncated : bool 174 | [] 175 | Versions : S3ObjectVersion[] 176 | } -------------------------------------------------------------------------------- /src/S3Provider/ProvidedTypes.fsi: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation 2005-2012. 2 | // This sample code is provided "as is" without warranty of any kind. 3 | // We disclaim all warranties, either express or implied, including the 4 | // warranties of merchantability and fitness for a particular purpose. 5 | 6 | // This file contains a set of helper types and methods for providing types in an implementation 7 | // of ITypeProvider. 8 | // 9 | // This code is a sample for use in conjunction with the F# 3.0 Developer Preview release of September 2011. 10 | 11 | 12 | namespace ProviderImplementation.ProvidedTypes 13 | 14 | open System 15 | open System.Reflection 16 | open System.Linq.Expressions 17 | open Microsoft.FSharp.Core.CompilerServices 18 | 19 | /// Represents an erased provided parameter 20 | type ProvidedParameter = 21 | inherit System.Reflection.ParameterInfo 22 | new : parameterName: string * parameterType: Type * ?isOut:bool * ?optionalValue:obj -> ProvidedParameter 23 | member IsParamArray : bool with get,set 24 | 25 | /// Represents an erased provided constructor. 26 | type ProvidedConstructor = 27 | inherit System.Reflection.ConstructorInfo 28 | 29 | /// Create a new provided constructor. It is not initially associated with any specific provided type definition. 30 | new : parameters: ProvidedParameter list -> ProvidedConstructor 31 | 32 | /// Add a 'System.Obsolete' attribute to this provided constructor 33 | member AddObsoleteAttribute : message: string * ?isError: bool -> unit 34 | 35 | /// Add XML documentation information to this provided constructor 36 | member AddXmlDoc : xmlDoc: string -> unit 37 | 38 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 39 | member AddXmlDocDelayed : xmlDocFunction: (unit -> string) -> unit 40 | 41 | /// Add XML documentation information to this provided constructor, where the documentation is re-computed every time it is required. 42 | member AddXmlDocComputed : xmlDocFunction: (unit -> string) -> unit 43 | 44 | /// Set the quotation used to compute the implementation of invocations of this constructor. 45 | member InvokeCode : (Quotations.Expr list -> Quotations.Expr) with set 46 | 47 | /// FSharp.Data addition: this method is used by Debug.fs 48 | member internal GetInvokeCodeInternal : bool -> (Quotations.Expr [] -> Quotations.Expr) 49 | 50 | /// Set the target and arguments of the base constructor call. Only used for generated types. 51 | member BaseConstructorCall : (Quotations.Expr list -> ConstructorInfo * Quotations.Expr list) with set 52 | 53 | /// Set a flag indicating that the constructor acts like an F# implicit constructor, so the 54 | /// parameters of the constructor become fields and can be accessed using Expr.GlobalVar with the 55 | /// same name. 56 | member IsImplicitCtor : bool with set 57 | 58 | /// Add definition location information to the provided constructor. 59 | member AddDefinitionLocation : line:int * column:int * filePath:string -> unit 60 | 61 | member IsTypeInitializer : bool with get,set 62 | 63 | type ProvidedMethod = 64 | inherit System.Reflection.MethodInfo 65 | 66 | /// Create a new provided method. It is not initially associated with any specific provided type definition. 67 | new : methodName:string * parameters: ProvidedParameter list * returnType: Type -> ProvidedMethod 68 | 69 | /// Add XML documentation information to this provided method 70 | member AddObsoleteAttribute : message: string * ?isError: bool -> unit 71 | 72 | /// Add XML documentation information to this provided constructor 73 | member AddXmlDoc : xmlDoc: string -> unit 74 | 75 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 76 | member AddXmlDocDelayed : xmlDocFunction: (unit -> string) -> unit 77 | 78 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 79 | /// The documentation is re-computed every time it is required. 80 | member AddXmlDocComputed : xmlDocFunction: (unit -> string) -> unit 81 | 82 | member AddMethodAttrs : attributes:MethodAttributes -> unit 83 | 84 | /// Set the method attributes of the method. By default these are simple 'MethodAttributes.Public' 85 | member SetMethodAttrs : attributes:MethodAttributes -> unit 86 | 87 | /// Get or set a flag indicating if the property is static. 88 | member IsStaticMethod : bool with get, set 89 | 90 | /// Set the quotation used to compute the implementation of invocations of this method. 91 | member InvokeCode : (Quotations.Expr list -> Quotations.Expr) with set 92 | 93 | /// FSharp.Data addition: this method is used by Debug.fs 94 | member internal GetInvokeCodeInternal : bool -> (Quotations.Expr [] -> Quotations.Expr) 95 | 96 | /// Add definition location information to the provided type definition. 97 | member AddDefinitionLocation : line:int * column:int * filePath:string -> unit 98 | 99 | 100 | 101 | /// Represents an erased provided property. 102 | type ProvidedProperty = 103 | inherit System.Reflection.PropertyInfo 104 | 105 | /// Create a new provided type. It is not initially associated with any specific provided type definition. 106 | new : propertyName: string * propertyType: Type * ?parameters:ProvidedParameter list -> ProvidedProperty 107 | 108 | /// Add a 'System.Obsolete' attribute to this provided property 109 | member AddObsoleteAttribute : message: string * ?isError: bool -> unit 110 | 111 | /// Add XML documentation information to this provided constructor 112 | member AddXmlDoc : xmlDoc: string -> unit 113 | 114 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 115 | member AddXmlDocDelayed : xmlDocFunction: (unit -> string) -> unit 116 | 117 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 118 | /// The documentation is re-computed every time it is required. 119 | member AddXmlDocComputed : xmlDocFunction: (unit -> string) -> unit 120 | 121 | /// Get or set a flag indicating if the property is static. 122 | /// FSharp.Data addition: the getter is used by Debug.fs 123 | member IsStatic : bool with get,set 124 | 125 | /// Set the quotation used to compute the implementation of gets of this property. 126 | member GetterCode : (Quotations.Expr list -> Quotations.Expr) with set 127 | 128 | /// Set the function used to compute the implementation of sets of this property. 129 | member SetterCode : (Quotations.Expr list -> Quotations.Expr) with set 130 | 131 | /// Add definition location information to the provided type definition. 132 | member AddDefinitionLocation : line:int * column:int * filePath:string -> unit 133 | 134 | /// Represents an erased provided property. 135 | type ProvidedEvent = 136 | inherit System.Reflection.EventInfo 137 | 138 | /// Create a new provided type. It is not initially associated with any specific provided type definition. 139 | new : propertyName: string * eventHandlerType: Type -> ProvidedEvent 140 | 141 | /// Add XML documentation information to this provided constructor 142 | member AddXmlDoc : xmlDoc: string -> unit 143 | 144 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 145 | member AddXmlDocDelayed : xmlDocFunction: (unit -> string) -> unit 146 | 147 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 148 | /// The documentation is re-computed every time it is required. 149 | member AddXmlDocComputed : xmlDocFunction: (unit -> string) -> unit 150 | 151 | /// Get or set a flag indicating if the property is static. 152 | member IsStatic : bool with set 153 | 154 | /// Set the quotation used to compute the implementation of gets of this property. 155 | member AdderCode : (Quotations.Expr list -> Quotations.Expr) with set 156 | 157 | /// Set the function used to compute the implementation of sets of this property. 158 | member RemoverCode : (Quotations.Expr list -> Quotations.Expr) with set 159 | 160 | /// Add definition location information to the provided type definition. 161 | member AddDefinitionLocation : line:int * column:int * filePath:string -> unit 162 | 163 | /// Represents an erased provided field. 164 | type ProvidedLiteralField = 165 | inherit System.Reflection.FieldInfo 166 | 167 | /// Create a new provided field. It is not initially associated with any specific provided type definition. 168 | new : fieldName: string * fieldType: Type * literalValue: obj -> ProvidedLiteralField 169 | 170 | /// Add a 'System.Obsolete' attribute to this provided field 171 | member AddObsoleteAttribute : message: string * ?isError: bool -> unit 172 | 173 | /// Add XML documentation information to this provided field 174 | member AddXmlDoc : xmlDoc: string -> unit 175 | 176 | /// Add XML documentation information to this provided field, where the computation of the documentation is delayed until necessary 177 | member AddXmlDocDelayed : xmlDocFunction: (unit -> string) -> unit 178 | 179 | /// Add XML documentation information to this provided field, where the computation of the documentation is delayed until necessary 180 | /// The documentation is re-computed every time it is required. 181 | member AddXmlDocComputed : xmlDocFunction: (unit -> string) -> unit 182 | 183 | /// Add definition location information to the provided field. 184 | member AddDefinitionLocation : line:int * column:int * filePath:string -> unit 185 | 186 | /// Represents an erased provided field. 187 | type ProvidedField = 188 | inherit System.Reflection.FieldInfo 189 | 190 | /// Create a new provided field. It is not initially associated with any specific provided type definition. 191 | new : fieldName: string * fieldType: Type -> ProvidedField 192 | 193 | /// Add a 'System.Obsolete' attribute to this provided field 194 | member AddObsoleteAttribute : message: string * ?isError: bool -> unit 195 | 196 | /// Add XML documentation information to this provided field 197 | member AddXmlDoc : xmlDoc: string -> unit 198 | 199 | /// Add XML documentation information to this provided field, where the computation of the documentation is delayed until necessary 200 | member AddXmlDocDelayed : xmlDocFunction: (unit -> string) -> unit 201 | 202 | /// Add XML documentation information to this provided field, where the computation of the documentation is delayed until necessary 203 | /// The documentation is re-computed every time it is required. 204 | member AddXmlDocComputed : xmlDocFunction: (unit -> string) -> unit 205 | 206 | /// Add definition location information to the provided field definition. 207 | member AddDefinitionLocation : line:int * column:int * filePath:string -> unit 208 | 209 | member SetFieldAttributes : attributes : FieldAttributes -> unit 210 | 211 | /// FSharp.Data addition: SymbolKind is used by AssemblyReplacer.fs 212 | /// Represents the type constructor in a provided symbol type. 213 | type SymbolKind = 214 | | SDArray 215 | | Array of int 216 | | Pointer 217 | | ByRef 218 | | Generic of System.Type 219 | | FSharpTypeAbbreviation of (System.Reflection.Assembly * string * string[]) 220 | 221 | /// FSharp.Data addition: ProvidedSymbolType is used by AssemblyReplacer.fs 222 | /// Represents an array or other symbolic type involving a provided type as the argument. 223 | /// See the type provider spec for the methods that must be implemented. 224 | /// Note that the type provider specification does not require us to implement pointer-equality for provided types. 225 | [] 226 | type ProvidedSymbolType = 227 | inherit System.Type 228 | 229 | /// Returns the kind of this symbolic type 230 | member Kind : SymbolKind 231 | /// Return the provided types used as arguments of this symbolic type 232 | member Args : list 233 | 234 | 235 | /// Provides symbolic provided types 236 | [] 237 | type ProvidedTypeBuilder = 238 | /// Like typ.MakeGenericType, but will also work with unit-annotated types 239 | static member MakeGenericType: genericTypeDefinition: System.Type * genericArguments: System.Type list -> System.Type 240 | /// Like methodInfo.MakeGenericMethod, but will also work with unit-annotated types and provided types 241 | static member MakeGenericMethod: genericMethodDefinition: System.Reflection.MethodInfo * genericArguments: System.Type list -> MethodInfo 242 | 243 | /// Helps create erased provided unit-of-measure annotations. 244 | [] 245 | type ProvidedMeasureBuilder = 246 | 247 | /// The ProvidedMeasureBuilder for building measures. 248 | static member Default : ProvidedMeasureBuilder 249 | 250 | /// e.g. 1 251 | member One : System.Type 252 | /// e.g. m * kg 253 | member Product : measure1: System.Type * measure1: System.Type -> System.Type 254 | /// e.g. 1 / kg 255 | member Inverse : denominator: System.Type -> System.Type 256 | 257 | /// e.g. kg / m 258 | member Ratio : numerator: System.Type * denominator: System.Type -> System.Type 259 | 260 | /// e.g. m * m 261 | member Square : ``measure``: System.Type -> System.Type 262 | 263 | /// the SI unit from the F# core library, where the string is in capitals and US spelling, e.g. Meter 264 | member SI : string -> System.Type 265 | 266 | /// e.g. float, Vector 267 | member AnnotateType : basic: System.Type * argument: System.Type list -> System.Type 268 | 269 | 270 | /// Represents a provided static parameter. 271 | type ProvidedStaticParameter = 272 | inherit System.Reflection.ParameterInfo 273 | new : parameterName: string * parameterType:Type * ?parameterDefaultValue:obj -> ProvidedStaticParameter 274 | 275 | /// Add XML documentation information to this provided constructor 276 | member AddXmlDoc : xmlDoc: string -> unit 277 | 278 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 279 | member AddXmlDocDelayed : xmlDocFunction: (unit -> string) -> unit 280 | 281 | /// Represents a provided type definition. 282 | type ProvidedTypeDefinition = 283 | inherit System.Type 284 | 285 | /// Create a new provided type definition in a namespace. 286 | new : assembly: Assembly * namespaceName: string * className: string * baseType: Type option -> ProvidedTypeDefinition 287 | 288 | /// Create a new provided type definition, to be located as a nested type in some type definition. 289 | new : className : string * baseType: Type option -> ProvidedTypeDefinition 290 | 291 | /// Add the given type as an implemented interface. 292 | member AddInterfaceImplementation : interfaceType: Type -> unit 293 | 294 | /// Add the given function as a set of on-demand computed interfaces. 295 | member AddInterfaceImplementationsDelayed : interfacesFunction:(unit -> Type list)-> unit 296 | 297 | /// Specifies that the given method body implements the given method declaration. 298 | member DefineMethodOverride : methodInfoBody: ProvidedMethod * methodInfoDeclaration: MethodInfo -> unit 299 | 300 | /// Add a 'System.Obsolete' attribute to this provided type definition 301 | member AddObsoleteAttribute : message: string * ?isError: bool -> unit 302 | 303 | /// Add XML documentation information to this provided constructor 304 | member AddXmlDoc : xmlDoc: string -> unit 305 | 306 | /// Set the base type 307 | member SetBaseType : Type -> unit 308 | 309 | /// Set the base type to a lazily evaluated value 310 | member SetBaseTypeDelayed : Lazy -> unit 311 | 312 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary. 313 | /// The documentation is only computed once. 314 | member AddXmlDocDelayed : xmlDocFunction: (unit -> string) -> unit 315 | 316 | /// Add XML documentation information to this provided constructor, where the computation of the documentation is delayed until necessary 317 | /// The documentation is re-computed every time it is required. 318 | member AddXmlDocComputed : xmlDocFunction: (unit -> string) -> unit 319 | 320 | /// Set the attributes on the provided type. This fully replaces the default TypeAttributes. 321 | member SetAttributes : System.Reflection.TypeAttributes -> unit 322 | 323 | /// Reset the enclosing type (for generated nested types) 324 | member ResetEnclosingType: enclosingType:System.Type -> unit 325 | 326 | /// Add a method, property, nested type or other member to a ProvidedTypeDefinition 327 | member AddMember : memberInfo:MemberInfo -> unit 328 | /// Add a set of members to a ProvidedTypeDefinition 329 | member AddMembers : memberInfos:list<#MemberInfo> -> unit 330 | 331 | /// Add a member to a ProvidedTypeDefinition, delaying computation of the members until required by the compilation context. 332 | member AddMemberDelayed : memberFunction:(unit -> #MemberInfo) -> unit 333 | 334 | /// Add a set of members to a ProvidedTypeDefinition, delaying computation of the members until required by the compilation context. 335 | member AddMembersDelayed : (unit -> list<#MemberInfo>) -> unit 336 | 337 | /// Add the types of the generated assembly as generative types, where types in namespaces get hierarchically positioned as nested types. 338 | member AddAssemblyTypesAsNestedTypesDelayed : assemblyFunction:(unit -> System.Reflection.Assembly) -> unit 339 | 340 | // Parametric types 341 | member DefineStaticParameters : parameters: ProvidedStaticParameter list * instantiationFunction: (string -> obj[] -> ProvidedTypeDefinition) -> unit 342 | 343 | /// Add definition location information to the provided type definition. 344 | member AddDefinitionLocation : line:int * column:int * filePath:string -> unit 345 | 346 | /// Suppress System.Object entries in intellisense menus in instances of this provided type 347 | member HideObjectMethods : bool with set 348 | 349 | /// Get or set a flag indicating if the ProvidedTypeDefinition is erased 350 | member IsErased : bool with get,set 351 | 352 | /// Get or set a flag indicating if the ProvidedTypeDefinition has type-relocation suppressed 353 | [] 354 | member SuppressRelocation : bool with get,set 355 | 356 | /// FSharp.Data addition: this method is used by Debug.fs 357 | member MakeParametricType : name:string * args:obj[] -> ProvidedTypeDefinition 358 | 359 | /// FSharp.Data addition: this method is used by Debug.fs and QuotationBuilder.fs 360 | /// Emulate the F# type provider type erasure mechanism to get the 361 | /// actual (erased) type. We erase ProvidedTypes to their base type 362 | /// and we erase array of provided type to array of base type. In the 363 | /// case of generics all the generic type arguments are also recursively 364 | /// replaced with the erased-to types 365 | static member EraseType : t:Type -> Type 366 | 367 | /// A provided generated assembly 368 | type ProvidedAssembly = 369 | new : assemblyFileName:string -> ProvidedAssembly 370 | /// 371 | /// Emit the given provided type definitions as part of the assembly 372 | /// and adjust the 'Assembly' property of all provided type definitions to return that 373 | /// assembly. 374 | /// 375 | /// The assembly is only emitted when the Assembly property on the root type is accessed for the first time. 376 | /// The host F# compiler does this when processing a generative type declaration for the type. 377 | /// 378 | /// An optional path of type names to wrap the generated types. The generated types are then generated as nested types. 379 | member AddTypes : types : ProvidedTypeDefinition list -> unit 380 | member AddNestedTypes : types : ProvidedTypeDefinition list * enclosingGeneratedTypeNames: string list -> unit 381 | 382 | #if FX_NO_LOCAL_FILESYSTEM 383 | #else 384 | /// Register that a given file is a provided generated assembly 385 | static member RegisterGenerated : fileName:string -> Assembly 386 | #endif 387 | 388 | 389 | /// A base type providing default implementations of type provider functionality when all provided 390 | /// types are of type ProvidedTypeDefinition. 391 | type TypeProviderForNamespaces = 392 | 393 | /// Initializes a type provider to provide the types in the given namespace. 394 | internal new : namespaceName:string * types: ProvidedTypeDefinition list -> TypeProviderForNamespaces 395 | 396 | /// Initializes a type provider 397 | internal new : unit -> TypeProviderForNamespaces 398 | 399 | /// Add a namespace of provided types. 400 | member internal AddNamespace : namespaceName:string * types: ProvidedTypeDefinition list -> unit 401 | 402 | /// FSharp.Data addition: this method is used by Debug.fs 403 | /// Get all namespace with their provided types. 404 | member Namespaces : (string * ProvidedTypeDefinition list) seq with get 405 | 406 | /// Invalidate the information provided by the provider 407 | member Invalidate : unit -> unit 408 | 409 | #if FX_NO_LOCAL_FILESYSTEM 410 | #else 411 | /// AssemblyResolve handler. Default implementation searches .dll file in registered folders 412 | abstract ResolveAssembly : System.ResolveEventArgs -> Assembly 413 | default ResolveAssembly : System.ResolveEventArgs -> Assembly 414 | 415 | /// Registers custom probing path that can be used for probing assemblies 416 | member RegisterProbingFolder : folder : string -> unit 417 | /// Registers location of RuntimeAssembly (from TypeProviderConfig) as probing folder 418 | member RegisterRuntimeAssemblyLocationAsProbingFolder : cfg : Core.CompilerServices.TypeProviderConfig -> unit 419 | #endif 420 | 421 | interface ITypeProvider -------------------------------------------------------------------------------- /src/S3Provider/Provider.fs: -------------------------------------------------------------------------------- 1 | // Container module for the S3 Type Provider 2 | // 3 | // ## Example 4 | // 5 | // type S3 = S3Provider.Account<"AWS Key", "AWS Secret"> 6 | // type bucket = S3.``my.bucket`` 7 | // type folder = bucket.``2013-12-13/`` 8 | // let etag = folder.``My file.txt``.ETag 9 | // let utf8 = folder.``My file.txt``.Content.UTF8 10 | // let raw = folder.``My image.png``.Content.Raw 11 | // let lastModified = folder.``My image.png``.LastModified 12 | // type search = bucket.Search<"2013-12-"> 13 | // let searchResultContent = search.``2013-12-13``.``My file.txt``.Content.Raw 14 | // 15 | namespace AwsProviders 16 | 17 | open System 18 | open System.Reflection 19 | open ProviderImplementation.ProvidedTypes 20 | open Microsoft.FSharp.Core.CompilerServices 21 | 22 | open AwsProvider.S3 23 | open AwsProvider.S3.Model 24 | 25 | module RuntimeHelper = 26 | let getDateTime str = DateTime.Parse(str) 27 | let getUtf8String = System.Text.Encoding.UTF8.GetString 28 | let getAsciiString = System.Text.Encoding.ASCII.GetString 29 | 30 | [] 31 | module internal Helpers = 32 | type Prefix = Prefix of string 33 | type FolderName = FolderName of string 34 | 35 | type S3Entry = 36 | | Folder of Prefix * FolderName 37 | | S3Object of IS3Object 38 | 39 | let erasedType<'T> assemblyName rootNamespace typeName = 40 | ProvidedTypeDefinition(assemblyName, rootNamespace, typeName, Some(typeof<'T>), HideObjectMethods = true) 41 | 42 | let runtimeType<'T> typeName = 43 | ProvidedTypeDefinition(typeName, Some typeof<'T>, HideObjectMethods = true) 44 | 45 | let thisAssembly = Assembly.GetExecutingAssembly() 46 | let rootNamespace = "S3Provider" 47 | 48 | /// Returns all the S3 buckets in the account 49 | let getBuckets awsCred = 50 | let result = S3Utils.listBuckets awsCred 51 | result.Buckets 52 | 53 | /// Returns whether or not the specified bucket has had versioning enabled at some point 54 | let isBucketVersioned awsCred (bucket : Bucket) = S3Utils.isBucketVersioned bucket.Name awsCred 55 | 56 | /// Returns a pretty name (without the folder prefixes) for the specified S3 object 57 | let getPrettyS3ObjectName (s3Object : IS3Object) = 58 | match s3Object.Key.LastIndexOf("/") with 59 | | -1 -> s3Object.Key 60 | | idx -> s3Object.Key.Substring(idx + 1) 61 | 62 | /// Returns a pretty name (without the folder prefixes) for the specified S3 object 63 | let getPrettyFolderName (Prefix prefix) = 64 | match prefix.LastIndexOf('/', prefix.Length - 2, prefix.Length - 1) with 65 | | -1 -> prefix 66 | | idx -> prefix.Substring(idx + 1) 67 | 68 | /// Returns all the S3 objects in the specified S3 bucket 69 | let getObjects awsCred (bucket : Bucket) (Prefix prefix) = 70 | let result = S3Utils.listBucket bucket.Name prefix awsCred 71 | 72 | let entries = 73 | [| 74 | if result.CommonPrefixes <> null then 75 | yield! result.CommonPrefixes 76 | |> Seq.map (fun prefixes -> 77 | let prefix = Prefix prefixes.Prefix 78 | Folder(prefix, FolderName <| getPrettyFolderName prefix)) 79 | 80 | if result.S3Objects <> null then 81 | yield! result.S3Objects |> Seq.map (fun s3Obj -> s3Obj :> IS3Object |> S3Object) 82 | |] 83 | 84 | // return whether or not there's more results, as well as the current set of results 85 | result.IsTruncated, entries 86 | 87 | /// Returns all the versions for the specified S3 object 88 | let getObjectVersions awsCred (bucket : Bucket) (s3Object : IS3Object) = 89 | let rec loop marker = seq { 90 | let result = S3Utils.listVersions bucket.Name s3Object.Key marker awsCred 91 | yield! result.Versions 92 | 93 | if not <| String.IsNullOrWhiteSpace result.NextVersionIdMarker then yield! loop (Some result.NextVersionIdMarker) 94 | } 95 | 96 | loop None |> Seq.toArray 97 | 98 | /// Returns the content (byte[]) of a S3 obejct 99 | let getContent awsCred (bucket : Bucket) (s3Object : IS3Object) = 100 | let version = match s3Object with 101 | | :? IS3ObjectVersion as objVersion -> Some objVersion.VersionId 102 | | _ -> None 103 | 104 | S3Utils.getContent bucket.Name s3Object.Key version awsCred 105 | 106 | /// Create a nested type to represent the content of a S3 object 107 | let createTypedContent (ownerType : ProvidedTypeDefinition) awsCred (bucket : Bucket) (s3Object : IS3Object) = 108 | let contents = getContent awsCred bucket s3Object 109 | let typedContent = runtimeType "Content" 110 | 111 | typedContent.AddMemberDelayed(fun () -> ProvidedProperty("UTF8", typeof, IsStatic = true, GetterCode = (fun args -> <@@ RuntimeHelper.getUtf8String(contents) @@>))) 112 | typedContent.AddMemberDelayed(fun () -> ProvidedProperty("ASCII", typeof, IsStatic = true, GetterCode = (fun args -> <@@ RuntimeHelper.getAsciiString(contents) @@>))) 113 | typedContent.AddMember(ProvidedProperty("Raw", typeof, IsStatic = true, GetterCode = (fun args -> <@@ contents @@>))) 114 | typedContent 115 | 116 | /// Create a nested type to represent a non-versioned S3 object 117 | let createTypedS3Object (ownerType : ProvidedTypeDefinition) awsCred (bucket : Bucket) typeName (s3Object : IS3Object) = 118 | let typeName = 119 | match typeName, s3Object with 120 | | Some name, _ -> name 121 | | _, (:? IS3ObjectVersion as s3ObjectVersion) 122 | -> if s3ObjectVersion.IsLatest 123 | then sprintf "(%s, Latest) %s" (s3ObjectVersion.LastModified.ToString("yyyy-MM-dd HH:mm:ss")) s3ObjectVersion.VersionId 124 | else sprintf "(%s) %s" (s3ObjectVersion.LastModified.ToString("yyyy-MM-dd HH:mm:ss")) s3ObjectVersion.VersionId 125 | | _ -> getPrettyS3ObjectName s3Object 126 | let typedS3Object = runtimeType typeName 127 | typedS3Object.AddXmlDoc(sprintf "A strongly typed interface to S3 object %s which is %d bytes in size" s3Object.Key s3Object.Size) 128 | 129 | let key, etag, size, lastModified, ownerId, ownerName = 130 | s3Object.Key, s3Object.ETag, s3Object.Size, s3Object.LastModified.ToString(), s3Object.Owner.Id, s3Object.Owner.DisplayName 131 | 132 | typedS3Object.AddMember(ProvidedProperty("ETag", typeof, IsStatic = true, GetterCode = (fun args -> <@@ etag @@>))) 133 | typedS3Object.AddMember(ProvidedProperty("Size", typeof, IsStatic = true, GetterCode = (fun args -> <@@ size @@>))) 134 | typedS3Object.AddMember(ProvidedProperty("LastModified", typeof, IsStatic = true, GetterCode = (fun args -> <@@ RuntimeHelper.getDateTime(lastModified) @@>))) 135 | typedS3Object.AddMember(ProvidedProperty("OwnerId", typeof, IsStatic = true, GetterCode = (fun args -> <@@ ownerId @@>))) 136 | typedS3Object.AddMember(ProvidedProperty("OwnerName", typeof, IsStatic = true, GetterCode = (fun args -> <@@ ownerName @@>))) 137 | typedS3Object.AddMemberDelayed(fun () -> createTypedContent typedS3Object awsCred bucket s3Object) 138 | 139 | typedS3Object 140 | 141 | /// Create a nested type to represent a versioned S3 object 142 | let createTypedVersionedS3Object (ownerType : ProvidedTypeDefinition) awsCred (bucket : Bucket) (s3Object : IS3Object) = 143 | let typedS3Object = getPrettyS3ObjectName s3Object |> runtimeType 144 | typedS3Object.AddXmlDoc(sprintf "A strongly typed interface to a versioned S3 object %s" s3Object.Key) 145 | 146 | // nested type to represent the latest version of the object 147 | typedS3Object.AddMember(createTypedS3Object ownerType awsCred bucket (Some "Latest") s3Object) 148 | 149 | // then a nested type called Versions to represent all the versions of the object 150 | let typedS3ObjectVersions = runtimeType "Versions" 151 | typedS3Object.AddMember(typedS3ObjectVersions) 152 | typedS3ObjectVersions.AddMembersDelayed(fun () -> 153 | let versions = getObjectVersions awsCred bucket s3Object 154 | versions |> Seq.map (createTypedS3Object ownerType awsCred bucket None) |> Seq.toList) 155 | 156 | typedS3Object 157 | 158 | /// Create a nested type to represent a S3 folder 159 | let rec createTypedS3Folder (ownerType : ProvidedTypeDefinition) awsCred (bucket : Bucket) isVersioned prefix folderName = 160 | let typedFolder = runtimeType folderName 161 | typedFolder.AddXmlDoc(sprintf "A strongly typed interface to a S3 folder %s" prefix) 162 | 163 | typedFolder.AddMembersDelayed(fun () -> createTypedS3Entries typedFolder awsCred bucket isVersioned prefix) 164 | 165 | typedFolder 166 | 167 | /// Create a nested type to represent a S3 entry (either Folder or S3Object) 168 | and createTypedS3Entry (ownerType : ProvidedTypeDefinition) awsCred bucket isVersioned = function 169 | | Folder(Prefix prefix, FolderName folderName) -> createTypedS3Folder ownerType awsCred bucket isVersioned prefix folderName 170 | | S3Object(s3Object) when isVersioned -> createTypedVersionedS3Object ownerType awsCred bucket s3Object 171 | | S3Object(s3Object) -> createTypedS3Object ownerType awsCred bucket None s3Object 172 | 173 | /// Create and return the list of nested types representing entries that are returned by the given prefix 174 | and createTypedS3Entries (ownerType : ProvidedTypeDefinition) awsCred bucket isVersioned prefix = 175 | let (isTruncated, entries) = getObjects awsCred bucket (Prefix prefix) 176 | 177 | seq { 178 | yield! entries |> Seq.map (createTypedS3Entry ownerType awsCred bucket isVersioned) 179 | if isTruncated then yield runtimeType "Too many results, use Search<...> instead" 180 | } 181 | |> Seq.toList 182 | 183 | /// Create a nested parametric type to represent a Search 184 | let createTypedSearch (ownerType : ProvidedTypeDefinition) awsCred (bucket : Bucket) isVersioned = 185 | let genericSearch = runtimeType "Search" 186 | 187 | let typeParams = [ ProvidedStaticParameter("prefix", typeof) ] 188 | let initFunction typeName (parameterValues : obj[]) = 189 | match parameterValues with 190 | | [| :? string as prefix |] -> 191 | let typedSearch = runtimeType typeName 192 | typedSearch.AddXmlDoc(sprintf "A strongly typed interface to a S3 search with prefix [%s]" prefix) 193 | typedSearch.AddMembersDelayed(fun () -> createTypedS3Entries typedSearch awsCred bucket isVersioned prefix) 194 | 195 | ownerType.AddMember(typedSearch) 196 | typedSearch 197 | 198 | genericSearch.DefineStaticParameters(parameters = typeParams, instantiationFunction = initFunction) 199 | genericSearch 200 | 201 | /// Create a nested type to represent a S3 bucket 202 | let createTypedBucket (ownerType : ProvidedTypeDefinition) awsCred (bucket : Bucket) = 203 | let typedBucket = runtimeType bucket.Name 204 | 205 | typedBucket.AddXmlDoc(sprintf "A strongly typed interface to S3 bucket %s which was created on %A" 206 | bucket.Name bucket.CreationDate) 207 | 208 | let creationDate = bucket.CreationDate.ToString() 209 | typedBucket.AddMember(ProvidedProperty("CreationDate", typeof, IsStatic = true, GetterCode = (fun args -> <@@ RuntimeHelper.getDateTime(creationDate) @@>))) 210 | typedBucket.AddMembersDelayed(fun () -> 211 | let isVersioned = isBucketVersioned awsCred bucket 212 | 213 | let typedSearch = createTypedSearch typedBucket awsCred bucket isVersioned 214 | let typedEntries = createTypedS3Entries typedBucket awsCred bucket isVersioned "" // use empty string as prefix for the top level bucket 215 | 216 | typedSearch :: typedEntries) 217 | 218 | typedBucket 219 | 220 | /// Create an erased type to represent a S3 account 221 | let createTypedAccount () = 222 | let typedS3 = erasedType thisAssembly rootNamespace "Account" 223 | 224 | let typeParams = [ ProvidedStaticParameter("awsKey", typeof); ProvidedStaticParameter("awsSecret", typeof) ] 225 | let initFunction (typeName : string) (parameterValues : obj[]) = 226 | match parameterValues with 227 | | [| :? string as awsKey; :? string as awsSecret |] -> 228 | let typedS3Account = erasedType thisAssembly rootNamespace typeName 229 | typedS3Account.AddXmlDoc(sprintf "A strongly typed interface to S3 account with key [%s] and secret [%s]" awsKey awsSecret) 230 | 231 | let awsCred = { AwsKey = awsKey; AwsSecret = awsSecret } 232 | 233 | typedS3Account.AddMembersDelayed(fun () -> getBuckets awsCred |> Seq.map (createTypedBucket typedS3Account awsCred) |> Seq.toList) 234 | 235 | typedS3Account 236 | 237 | typedS3.DefineStaticParameters(parameters = typeParams, instantiationFunction = initFunction) 238 | typedS3 239 | 240 | [] 241 | type S3Provider (config : TypeProviderConfig) as this = 242 | inherit TypeProviderForNamespaces () 243 | 244 | do this.AddNamespace(rootNamespace, [ createTypedAccount() ]) 245 | 246 | [] 247 | do () -------------------------------------------------------------------------------- /src/S3Provider/S3Provider.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA} 8 | Library 9 | S3Provider 10 | S3Provider 11 | v4.0 12 | 4.3.0.0 13 | S3Provider 14 | 15 | ..\..\ 16 | true 17 | 18 | 19 | true 20 | full 21 | false 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | 3 26 | bin\Debug\S3Provider.XML 27 | 28 | 29 | pdbonly 30 | true 31 | true 32 | ..\..\bin 33 | TRACE 34 | 3 35 | ..\..\bin\S3Provider.XML 36 | 37 | 38 | 11 39 | 40 | 41 | 42 | 43 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 44 | 45 | 46 | 47 | 48 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | ..\..\packages\FSharp.Core.3.1.2.1\lib\net40\FSharp.Core.dll 71 | 72 | 73 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/S3Provider/Utils.fs: -------------------------------------------------------------------------------- 1 | namespace AwsProvider.S3 2 | 3 | open System 4 | open System.Globalization 5 | open System.IO 6 | open System.Linq 7 | open System.Net 8 | open System.Xml.Serialization 9 | open System.Security.Cryptography 10 | open System.Text 11 | 12 | open AwsProvider.S3.Model 13 | 14 | /// To find out more on REST authentication with S3, please read: 15 | /// http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html 16 | /// the rest of the code assumes a path-style request, i.e. instead of 17 | /// https://johnsmith.s3.amazonaws.com/photos/puppy.jpg 18 | /// the URI used will be 19 | /// https://s3.amazonaws.com/johnsmith/photos/puppy.jpg 20 | 21 | module S3Utils = 22 | let baseUri = Uri "http://s3.amazonaws.com" 23 | let userAgent = "S3Provider (https://github.com/theburningmonk/S3Provider/)" 24 | let subresources = [| "acl"; "cors"; "delete"; "lifecycle"; "location"; "logging"; "notification"; "partNumber"; "policy"; "requestPayment"; "restore"; "tagging"; "torrent"; "uploadId"; "uploads"; "versionId"; "versioning"; "versions"; "website" |] 25 | |> Set.ofArray 26 | 27 | let getTimestampRFC822 (date : DateTime) = 28 | date.ToString("ddd, dd MMM yyyy HH:mm:ss \\G\\M\\T", CultureInfo.InvariantCulture) 29 | 30 | let getCannonicalResource (relativePath : string) = 31 | let path, subresources = 32 | match relativePath.IndexOf('?') with 33 | | -1 -> relativePath, [||] 34 | | idx -> 35 | let path = relativePath.Substring(0, idx) 36 | let subresources = 37 | relativePath.Substring(idx + 1).Split([| '&'; ';' |], StringSplitOptions.RemoveEmptyEntries) 38 | |> Array.map (fun str -> str.Split('=')) 39 | // only keep resources that have null values (e.g. acl, versions) or have non-empty values 40 | |> Array.filter (function | [| param |] when subresources.Contains param -> true 41 | | [| param; value |] 42 | when subresources.Contains param && value <> "" -> true 43 | | _ -> false) 44 | path, subresources 45 | 46 | match subresources with 47 | | [||] -> path 48 | | subresources -> 49 | subresources 50 | // null-value resources (e.g. acl, versions) come first 51 | .OrderBy(fun arr -> arr.Length) 52 | // other resources are ordered alphabeticaly 53 | .ThenBy(fun arr -> arr.[0]) 54 | |> Seq.map (function | [| param |] -> param | [| param; value |] -> sprintf "%s=%s" param value) 55 | |> fun seq -> String.Join("&", seq) 56 | |> fun sub -> sprintf "%s?%s" path sub 57 | 58 | let getCannonicalAmzHeaders (headers : WebHeaderCollection) = 59 | headers.AllKeys 60 | |> Seq.filter (fun key -> key.ToLower().StartsWith("x-amz")) 61 | |> Seq.sort 62 | |> Seq.map (fun key -> sprintf "%s:%s" key headers.[key]) 63 | |> Seq.map (fun str -> str.Trim()) 64 | |> fun lst -> String.Join("\n", lst) 65 | 66 | let getStringToSign relativePath headers date = 67 | // no Content-MD5 and Content-Type headers since we're doing a GET 68 | "GET\n\n\n" + date + "\n" + getCannonicalAmzHeaders headers + getCannonicalResource relativePath 69 | 70 | let getSignature { AwsSecret = secret } (payload : string) = 71 | let data = Encoding.UTF8.GetBytes(payload) 72 | let algo = KeyedHashAlgorithm.Create("HMACSHA1") 73 | algo.Key <- Encoding.UTF8.GetBytes(secret) 74 | algo.ComputeHash(data) |> Convert.ToBase64String 75 | 76 | /// Creates a HttpWebRequest for the specified relative path 77 | let createRequest (relativePath : string) awsCred = 78 | let uri = Uri(baseUri, relativePath) 79 | let req = WebRequest.Create(uri) :?> HttpWebRequest 80 | req.Timeout <- Int32.MaxValue 81 | req.ReadWriteTimeout <- Int32.MaxValue 82 | req.AllowWriteStreamBuffering <- false 83 | 84 | req.Date <- DateTime.UtcNow 85 | req.UserAgent <- userAgent 86 | let dateString = getTimestampRFC822 req.Date 87 | let stringToSign = getStringToSign relativePath req.Headers dateString 88 | printfn "%s" stringToSign 89 | 90 | let signature = stringToSign |> getSignature awsCred 91 | let authorization = sprintf "AWS %s:%s" awsCred.AwsKey signature 92 | req.Headers.Add("Authorization", authorization) 93 | 94 | req 95 | 96 | let executeRequest<'T> (req : HttpWebRequest) = 97 | let response = req.GetResponse() 98 | use stream = response.GetResponseStream() 99 | let serializer = new XmlSerializer(typeof<'T>) 100 | serializer.Deserialize(stream) :?> 'T 101 | 102 | let listBuckets = createRequest "/" >> executeRequest 103 | 104 | let isBucketVersioned bucketName = 105 | sprintf "/%s/?versioning" bucketName 106 | |> createRequest 107 | >> executeRequest 108 | >> fun config -> match config.Status with 109 | | "Enabled" | "enabled" 110 | | "Suspended" | "suspended" -> true 111 | | _ -> false 112 | 113 | let listBucket bucketName prefix = 114 | sprintf "/%s/?prefix=%s&max-keys=1000&delimiter=/" bucketName prefix 115 | |> createRequest 116 | >> executeRequest 117 | 118 | let listVersions bucketName key versionIdMarker = 119 | let relPath = 120 | match versionIdMarker with 121 | | Some marker -> sprintf "/%s/?versions&prefix=%s&version-id-marker=%s&key-marker=%s&max-keys=1000&delimiter=/" bucketName key marker key 122 | | _ -> sprintf "/%s/?versions&prefix=%s&max-keys=1000&delimiter=/" bucketName key 123 | 124 | relPath 125 | |> createRequest 126 | >> executeRequest 127 | 128 | let getContent bucketName key version = 129 | let relPath = match version with 130 | | Some versionId -> sprintf "/%s/%s?versionId=%s" bucketName key versionId 131 | | _ -> sprintf "/%s/%s" bucketName key 132 | 133 | createRequest relPath 134 | >> (fun req -> 135 | use responseStream = req.GetResponse().GetResponseStream() 136 | use memStream = new MemoryStream() 137 | responseStream.CopyTo(memStream) 138 | memStream.ToArray()) -------------------------------------------------------------------------------- /src/S3Provider/Utils.fsi: -------------------------------------------------------------------------------- 1 | namespace AwsProvider.S3 2 | 3 | open AwsProvider.S3.Model 4 | 5 | module S3Utils = 6 | val listBuckets : (AwsCredential -> ListAllMyBucketsResult) 7 | val isBucketVersioned : bucketName : string -> (AwsCredential -> bool) 8 | val listBucket : bucketName : string -> prefix : string -> (AwsCredential -> ListBucketResult) 9 | val listVersions : bucketName : string -> key : string -> versionIdMarker : string option -> (AwsCredential -> ListVersionsResult) 10 | val getContent : bucketName : string -> key : string -> version : string option -> (AwsCredential -> byte[]) -------------------------------------------------------------------------------- /src/S3Provider/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/S3Provider.Tests/Program.fs: -------------------------------------------------------------------------------- 1 | module Program 2 | 3 | open Fuchu 4 | 5 | [] 6 | let main argv = 7 | Tests.defaultMainThisAssembly argv -------------------------------------------------------------------------------- /tests/S3Provider.Tests/S3Provider.Tests.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F} 8 | Exe 9 | S3Provider.Tests 10 | S3Provider.Tests 11 | v4.0 12 | 4.3.0.0 13 | S3Provider.Tests 14 | 15 | ..\..\ 16 | true 17 | 18 | 19 | true 20 | full 21 | false 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | 3 26 | bin\Debug\S3Provider.Tests.XML 27 | Project 28 | 29 | 30 | 31 | 32 | 33 | 34 | pdbonly 35 | true 36 | true 37 | bin\Release\ 38 | TRACE 39 | 3 40 | bin\Release\S3Provider.Tests.XML 41 | 42 | 43 | 11 44 | 45 | 46 | 47 | 48 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 49 | 50 | 51 | 52 | 53 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | ..\..\packages\Fuchu.0.4.0.0\lib\Fuchu.dll 66 | 67 | 68 | ..\..\packages\FSharp.Core.3.1.2.1\lib\net40\FSharp.Core.dll 69 | 70 | 71 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /tests/S3Provider.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | --------------------------------------------------------------------------------