Compare commits

..

1602 Commits

Author SHA1 Message Date
Harshavardhana daa113d89d Merge pull request #651 from harshavardhana/pr_out_migrating_minio_server_build_to_do_go_run_make_go_style_like_mc 2015-06-16 20:27:31 -07:00
Harshavardhana 8bde4d4e34 Migrating minio server build to do 'go run make.go' style like mc 2015-06-16 20:23:02 -07:00
Harshavardhana 4998907835 Update README.md 2015-06-16 16:09:10 -07:00
Harshavardhana bbc6c056e8 Update README.md 2015-06-16 16:03:17 -07:00
Harshavardhana db666a1f6e Update README.md 2015-06-16 15:58:04 -07:00
Harshavardhana 6b8766790b Merge pull request #650 from harshavardhana/pr_out_add_time_since_on_buckets_created_time_to_avoid_deleting_buckets_spuriously_during_eviction_of_objects 2015-06-13 11:30:06 -07:00
Harshavardhana d4e71beb54 Add time.Since on buckets created time to avoid deleting buckets spuriously during eviction of objects 2015-06-13 11:28:04 -07:00
Harshavardhana da593b498c Merge pull request #649 from harshavardhana/pr_out_minor_optimization_avoiding_one_unnecessary_copy
Minor optimization avoiding one unnecessary copy
2015-06-11 14:26:18 -07:00
Harshavardhana 636788997b Minor optimization avoiding one unnecessary copy 2015-06-11 14:23:05 -07:00
Harshavardhana 609c587a27 Merge pull request #648 from harshavardhana/pr_out_make_sure_to_reply_back_etag_with_quotes_for_s3_compliance
Make sure to reply back ETag with quotes for s3 compliance
2015-06-09 01:14:49 -07:00
Harshavardhana 6d44274db6 Make sure to reply back ETag with quotes for s3 compliance 2015-06-09 01:13:02 -07:00
Harshavardhana 0c5aa7a3d8 Merge pull request #647 from harshavardhana/pr_out_remove_unnecessary_tlshelpers_ssl_works_with_domain_certificate 2015-06-08 20:57:10 -07:00
Harshavardhana a947767339 Remove unnecessary tlsHelpers, SSL works with domain certificate 2015-06-08 20:54:41 -07:00
Harshavardhana 666ed34059 Merge pull request #646 from harshavardhana/pr_out_enable_tls_and_use_it 2015-06-08 20:13:17 -07:00
Harshavardhana c6ecd94420 Enable TLS and use it 2015-06-08 20:10:59 -07:00
Harshavardhana dcc1609d2e Merge pull request #645 from harshavardhana/pr_out_return_back_entity_too_large_for_objects_bigger_than_cache_size
Return back entity too large for objects bigger than cache size
2015-06-08 17:12:22 -07:00
Harshavardhana 64b014369c Return back entity too large for createObject requests bigger than cache size 2015-06-08 17:10:07 -07:00
Harshavardhana 5edd8cce3d Merge pull request #644 from harshavardhana/pr_out_load_from_persisted_multipart_session_now_multipart_uploads_can_resume_even_after_restarting_minio_fs_server 2015-06-08 15:17:43 -07:00
Harshavardhana ab1976bc14 Load from persisted multipart session, now multipart uploads can resume even after restarting minio fs server 2015-06-08 15:15:37 -07:00
Harshavardhana 4d2eab78d8 Merge pull request #643 from harshavardhana/pr_out_more_multipart_fixes_filter_out_parts_and_multipart_metadata_from_listobjects
More multipart fixes, filter out parts and multipart metadata from listObjects
2015-06-08 14:15:07 -07:00
Harshavardhana 2976f109df More multipart fixes, filter out parts and multipart metadata from listObjects 2015-06-08 14:08:36 -07:00
Harshavardhana 765fb08e20 Merge pull request #642 from harshavardhana/multipartfixes
fs multipart fixes
2015-06-08 12:31:41 -07:00
Harshavardhana e08d59be00 Make sure to delete uploadid's from active session file properly 2015-06-08 12:25:51 -07:00
Harshavardhana 0d3710cb9b Store in json file instead of gob for fs metadata 2015-06-08 12:08:01 -07:00
Harshavardhana 50994d7d71 Merge pull request #641 from harshavardhana/pr_out_fix_erroneous_new_line_in_helptemplate
Fix erroneous new line in helptemplate
2015-06-08 11:59:14 -07:00
Harshavardhana 0571ad0b83 Fix erroneous new line in helptemplate 2015-06-08 11:57:14 -07:00
Harshavardhana 8671057005 Merge pull request #640 from harshavardhana/pr_out_add_delete_handlers_and_reply_back_as_notimplemented_instead_of_404
Add delete handlers and reply back as 'NotImplemented' instead of 404
2015-06-08 11:08:59 -07:00
Harshavardhana 8efc842b59 Add delete handlers and reply back as 'NotImplemented' instead of 404 2015-06-08 11:06:06 -07:00
Harshavardhana 69366e20d3 Merge pull request #639 from harshavardhana/pr_out_enhance_logging_handler_to_print_in_humanize_form_for_contentlength 2015-06-08 02:17:01 -07:00
Harshavardhana 8a320c4447 Enhance logging handler to print in humanize form for ContentLength 2015-06-08 02:14:09 -07:00
Harshavardhana 2d5c48a973 Merge pull request #638 from harshavardhana/pr_out_update_gorilla_mux_and_go_humanize
Update gorilla mux and go-humanize
2015-06-08 01:38:48 -07:00
Harshavardhana b45e23b958 Update gorilla mux and go-humanize 2015-06-08 01:36:07 -07:00
Harshavardhana 964355206d Merge pull request #637 from harshavardhana/pr_out_put_back_the_older_conn_limit 2015-06-06 18:12:04 -07:00
Harshavardhana cefd740002 Put back the older conn_limit 2015-06-06 18:11:38 -07:00
Harshavardhana 78c0f85eb0 Merge pull request #636 from harshavardhana/pr_out_an_attempt_to_make_connection_limit_bufferred_channel_wip 2015-06-06 18:08:09 -07:00
Harshavardhana 371651bde6 Add rate limiter instead of connection limit for now 2015-06-06 18:04:55 -07:00
Harshavardhana 996c1a5c28 Merge pull request #635 from harshavardhana/pr_out_fix_a_deadlock_in_trove_when_evicting_objects_when_we_reach_the_maxsize_used
Fix a deadlock in trove when evicting objects when we reach the maxSize used
2015-06-06 16:06:53 -07:00
Harshavardhana 21916dc0a1 Fix a deadlock in trove when evicting objects when we reach the maxSize used 2015-06-06 16:02:52 -07:00
Harshavardhana d78832fb39 Merge pull request #634 from harshavardhana/pr_out_make_connection_limit_configurable 2015-06-06 14:33:56 -07:00
Harshavardhana 8b43655d9f Make connection limit configurable 2015-06-06 14:31:50 -07:00
Anand Babu (AB) Periasamy 6263b99e5a Merge pull request #633 from minio/reorganize-commands
reorganize commands
2015-06-05 18:32:22 -07:00
Anand Babu (AB) Periasamy 2604ffa42a reorganize commands 2015-06-05 18:29:24 -07:00
Harshavardhana 391e03881d Merge pull request #632 from harshavardhana/pr_out_do_not_attempt_to_restore_while_saving_new_deps 2015-06-04 16:35:49 -07:00
Harshavardhana 5101273ec7 Do not attempt to restore while saving new deps 2015-06-04 16:32:35 -07:00
Harshavardhana 962f5d5160 Merge pull request #631 from harshavardhana/pr_out_implement_custom_date_command_for_cross_platform_portability 2015-06-04 12:35:08 -07:00
Harshavardhana 5d484e2770 Implement custom date command for cross platform portability 2015-06-04 12:32:23 -07:00
Harshavardhana 23861fa6a7 Merge pull request #630 from harshavardhana/pr_out_misc_changes_before_capturing_proper_video 2015-06-03 18:31:16 -07:00
Harshavardhana a344f5b34d Misc changes before capturing proper video
- Disable management UI command option
- Remove featureflags option, filesystem and memory already support multipart
- Print informative messages after starting minio server
2015-06-03 18:27:15 -07:00
Harshavardhana a5b9c4fd26 Merge pull request #629 from harshavardhana/pr_out_enable_filesystem_for_api_tests_this_patch_also_implements_listmultipartuploads_ 2015-06-01 20:59:06 -07:00
Harshavardhana 097f70a3c5 Enable filesystem for API tests, this patch also implements ListMultipartUploads() 2015-06-01 20:57:13 -07:00
Harshavardhana bf36fcb6f7 Merge pull request #628 from harshavardhana/pr_out_skip_files_and_weird_directories_from_listbuckets_allowing_this_so_that_minio_fs_mode_can_be_used_as_ftp_service
Skip files and weird directories from listBuckets(), allowing this so that minio fs mode can be used as ftp service
2015-06-01 16:46:51 -07:00
Harshavardhana bfb9209689 Skip files and weird directories from listBuckets(), allowing this so that minio fs mode can be used as ftp service 2015-06-01 16:43:43 -07:00
Harshavardhana b038c4bd7f Merge pull request #627 from harshavardhana/pr_out_implement_multipart_support 2015-06-01 16:28:26 -07:00
Harshavardhana d86ba5f336 Implement multipart support
- implemented NewMultipartUpload()
 - implemented CreateObjectPart()
 - implemented ListObjectParts()
 - implemented AbortMultipartUpload()
 - implemented CompleteMultipartUpload()
2015-06-01 16:25:11 -07:00
Harshavardhana 00a976adf1 Merge pull request #626 from harshavardhana/pr_out_errorresponse_from_minio_server_needed_proper_xml_translations 2015-06-01 12:22:48 -07:00
Harshavardhana c07d48e7e8 ErrorResponse from minio server needed proper xml translations 2015-06-01 12:19:27 -07:00
Harshavardhana e1270bcdf6 Merge pull request #625 from harshavardhana/pr_out_make_caching_a_package_trove_and_use_it_inside_memory_driver 2015-05-31 18:43:47 -07:00
Harshavardhana a91e519692 Make caching a package trove, and use it inside memory driver 2015-05-31 18:41:56 -07:00
Harshavardhana 122d67625f Merge pull request #624 from vadmeste/pr_out_protect_exported_memory_object_api_by_a_mutex
Protect the exported method Delete() by a lock
2015-05-31 12:34:02 -07:00
Anis Elleuch 7e5a26f42c Protect the exported method Delete() 2015-05-31 20:29:42 +01:00
Harshavardhana 437c2b31dd Merge pull request #622 from harshavardhana/pr_out_add_filesystem_factory_functions_and_add_related_cli_options 2015-05-30 03:26:58 -07:00
Harshavardhana 82a0eac659 Add filesystem factory functions and add related cli options 2015-05-30 03:23:06 -07:00
Harshavardhana 0cc63706bb Resurrect back fileystem driver 2015-05-30 03:12:01 -07:00
Harshavardhana 56566d055e Merge pull request #621 from vadmeste/pr_out_forbid_upload_of_file_bigger_than_memory_backend 2015-05-28 14:09:41 -07:00
Anis Elleuch d360d0fec3 Forbid the upload of files bigger than the memory backend capacity 2015-05-28 22:07:02 +01:00
Harshavardhana ab80057c5c Update README.md add asciinema video for minio 2015-05-27 20:16:38 -07:00
Harshavardhana cb2a0f774a Update README.md 2015-05-27 18:54:03 -07:00
Harshavardhana 079615a104 Update CONTRIBUTING.md 2015-05-27 18:41:14 -07:00
Harshavardhana 0371ff7242 Merge pull request #619 from minio/harshavardhana-patch-1
Rename BUILDDEPS.md to INSTALLGO.md
2015-05-27 18:38:08 -07:00
Harshavardhana a23f449734 Merge pull request #620 from minio/harshavardhana-patch-2
Update README.md
2015-05-27 18:37:25 -07:00
Harshavardhana d89118e3b6 Update README.md 2015-05-27 18:34:42 -07:00
Harshavardhana cfa4329d21 Rename BUILDDEPS.md to INSTALLGO.md 2015-05-27 17:56:54 -07:00
Harshavardhana 7506227a77 Update BUILDDEPS.md 2015-05-27 17:51:20 -07:00
Harshavardhana 82f267706b Merge pull request #618 from minio/harshavardhana-build-dep
Update BUILDDEPS.md
2015-05-27 17:46:45 -07:00
Harshavardhana 2cbd4e00df Update BUILDDEPS.md 2015-05-27 17:43:39 -07:00
Harshavardhana 66967b8ec0 Merge pull request #617 from harshavardhana/pr_out_fix_erroneous_build_date_formatting 2015-05-26 02:18:27 -07:00
Harshavardhana ddfa964025 Fix erroneous build date formatting 2015-05-26 02:14:54 -07:00
Harshavardhana 554a244b47 Add donut OSX support 2015-05-26 02:14:34 -07:00
Harshavardhana 92a37e5113 Merge pull request #615 from harshavardhana/pr_out_use_http_timeformat_to_return_s3_expects_us_to_return_in_gmt_not_utc 2015-05-25 20:18:52 -07:00
Harshavardhana e46660a966 Use http.TimeFormat to return, S3 expects us to return in GMT not UTC 2015-05-25 20:17:04 -07:00
Harshavardhana 4b22a90182 Merge pull request #614 from harshavardhana/pr_out_handle_authorization_header_better
Handle authorization header better
2015-05-24 21:02:47 -07:00
Harshavardhana 19250296c6 Handle authorization header better 2015-05-24 20:59:53 -07:00
Harshavardhana 2d5e1d3797 Merge pull request #613 from harshavardhana/pr_out_relax_minium_object_size_limit_one_can_really_upload_a_0byte_file 2015-05-23 12:22:27 -07:00
Harshavardhana 9666f2e5bf Relax minium object size limit, one can really upload a 0byte file
For example
~~~
$ mc ls https://s3.amazonaws.com/ferenginar/test.go
[2015-05-23 12:02:06 PDT]     0B test.go

$ curl -i -X HEAD https://s3.amazonaws.com/ferenginar/test.go
HTTP/1.1 200 OK
x-amz-id-2: ZMWLriPH+uQJ8IsaMHmuNOU/FXvdSq+s6O7ugUI9hZ695XJTNAZ1utKxh03w5Jcf
x-amz-request-id: F5A11F533B74DD8F
Date: Sat, 23 May 2015 19:19:29 GMT
Last-Modified: Sat, 23 May 2015 19:02:06 GMT
ETag: "d41d8cd98f00b204e9800998ecf8427e"
Accept-Ranges: bytes
Content-Type: binary/octet-stream
Content-Length: 0
Server: AmazonS3
~~~
2015-05-23 12:19:16 -07:00
Harshavardhana d89396e2f0 Merge pull request #612 from harshavardhana/pr_out_add_contributors_file 2015-05-23 11:55:55 -07:00
Harshavardhana eca8087993 Add contributors file 2015-05-23 11:49:07 -07:00
Harshavardhana c63ba4be26 Merge pull request #611 from harshavardhana/pr_out_add_missing_validate_access_keys_after_extracted_from_authheader 2015-05-21 19:29:19 -07:00
Harshavardhana e11f9110b6 add missing validate access keys after being extracted from AuthHeader 2015-05-21 19:23:47 -07:00
Harshavardhana 138288f788 Merge pull request #610 from harshavardhana/pr_out_fix_some_donut_todo_s_regarding_bucket_created_date 2015-05-21 11:17:24 -07:00
Harshavardhana ad60b97d52 Fix some donut TODO's regarding bucket created date 2015-05-21 11:13:49 -07:00
Harshavardhana 39dac2afac Merge pull request #609 from harshavardhana/pr_out_remove_unnecessary_todo_for_httpserver 2015-05-21 02:59:12 -07:00
Harshavardhana cd817d34df Finish last bits of api testsuite on server 2015-05-21 02:57:03 -07:00
Harshavardhana 0fbd36e18e Merge pull request #608 from harshavardhana/pr_out_remove_bitdell_and_analytics_badge_these_services_are_not_working_anymore 2015-05-20 17:20:54 -07:00
Harshavardhana d4bb71f6fd Remove bitdell and analytics badge, these services are not working anymore 2015-05-20 17:18:15 -07:00
Harshavardhana f1fecd7510 Merge pull request #607 from harshavardhana/pr_out_bump_gocyclo_back_to_16 2015-05-19 18:34:38 -07:00
Harshavardhana f00bfd38da Bump gocyclo back to 16 2015-05-19 18:32:50 -07:00
Harshavardhana b84d8fcda7 Merge pull request #606 from harshavardhana/pr_out_fix_duplicate_map_allocation 2015-05-18 13:18:04 -07:00
Harshavardhana 3d61ba5930 Fix duplicate map allocation 2015-05-18 13:14:01 -07:00
Harshavardhana 8ce44bfbd1 Merge pull request #605 from harshavardhana/pr_out_update_totalnumber_of_multiparts_inside_createobjectpart_also_introduce_support_for_uploadidmarker_and_prefix_for_listmultipartuploads 2015-05-18 12:27:05 -07:00
Harshavardhana e4c0d574dc Update totalnumber of multiparts inside CreateObjectPart(), also introduce support for UploadIDMarker and Prefix for listMultipartUploads 2015-05-18 12:24:36 -07:00
Harshavardhana b3e0b3e4dc Merge pull request #604 from harshavardhana/pr_out_head_request_should_have_content_length_for_only_successful_response_there_is_no_response_body_for_errors_just_header_is_sufficient_fixes_603 2015-05-15 21:58:55 -07:00
Harshavardhana 7ce47130fd HEAD request should have Content-Length for only successful response, there is no response body for errors, just header is sufficient - fixes #603
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13

"""  in the case of the HEAD method, the size of the entity-body that would have been sent had the request been a GET. """
2015-05-15 21:55:59 -07:00
Harshavardhana b0925965a7 Merge pull request #602 from harshavardhana/pr_out_remove_redundant_writeheader_calls 2015-05-15 21:00:32 -07:00
Harshavardhana 317637fcb8 Remove redundant WriteHeader calls 2015-05-15 20:58:28 -07:00
Harshavardhana 5c5761ae16 Remove unnecessary GetObjectMetadata prefix argument 2015-05-15 19:25:17 -07:00
Harshavardhana 8ad52364da Merge pull request #601 from harshavardhana/pr_out_for_multiparts_use_its_own_cache_avoids_deadlocks_during_eviction_wip
For multiparts use its own cache avoids deadlocks during expiration
2015-05-14 20:29:15 -07:00
Harshavardhana 6275238a47 For multiparts use its own cache avoids deadlocks during object expiration
Using same object cache as regular objects for multiparts causes deadlocks during object expiration routine.

As a side affect this also fixes the bug of listing multiparts during regular 'listing' of objects.
2015-05-14 20:26:59 -07:00
Harshavardhana 5751b0bf36 Merge pull request #600 from harshavardhana/pr_out_fixing_a_race_in_newmultipartupload_session_for_simultaneous_requests_observed_at_play_minio_io 2015-05-14 19:13:44 -07:00
Harshavardhana c41ebf7535 Fixing a race in NewMultipartUpload() session for simultaneous requests, observed at play.minio.io 2015-05-14 19:11:19 -07:00
Harshavardhana eb34634e81 Merge pull request #599 from harshavardhana/pr_out_add_more_tests_for_multipart_now_in_driver_api_testsuite 2015-05-14 17:31:29 -07:00
Harshavardhana 8fb427a892 Add more tests for multipart now in driver api_testsuite 2015-05-14 17:28:39 -07:00
Harshavardhana 06a9e468d6 Merge pull request #598 from harshavardhana/pr_out_add_tests_for_abortmultipartupload_listobjectparts_listmultipartuploads 2015-05-14 17:09:57 -07:00
Harshavardhana dba7c94571 Add tests for abortMultipartUpload, listobjectparts, listmultipartuploads 2015-05-14 17:07:30 -07:00
Harshavardhana 5f381a8bee Merge pull request #597 from harshavardhana/pr_out_an_attempt_to_implement_listmultipartuploads_ 2015-05-14 16:25:37 -07:00
Harshavardhana 1bd94ec6ab An attempt to implement ListMultipartUploads() 2015-05-14 16:22:47 -07:00
Harshavardhana 4f7ae8af92 Merge pull request #596 from harshavardhana/pr_out_avoid_one_last_memory_copy_wip 2015-05-14 11:29:59 -07:00
Harshavardhana 82b043005a Avoid one last memory copy 2015-05-14 11:26:55 -07:00
Harshavardhana 55b9a5f5e4 Merge pull request #595 from harshavardhana/pr_out_add_a_new_validatecontenttypehandler_verify_accept_header_earlier 2015-05-13 12:26:30 -07:00
Harshavardhana 5498c90788 Add a new validateContentTypeHandler{}, verify Accept header earlier 2015-05-13 12:22:15 -07:00
Harshavardhana fdbfa5070b Merge pull request #593 from harshavardhana/pr_out_more_scripts_and_code_from_minio_io_to_minio 2015-05-11 16:43:54 -07:00
Harshavardhana de56909d55 More scripts and code from Minio-io to minio 2015-05-11 16:43:38 -07:00
Harshavardhana 946341ac29 Merge pull request #592 from harshavardhana/pr_out_move_cli_check_to_minio_from_minio_io 2015-05-11 16:40:23 -07:00
Harshavardhana 50559cfd65 Move cli, check to minio from minio-io 2015-05-11 16:40:12 -07:00
Harshavardhana f5fb701c5c Merge pull request #591 from harshavardhana/pr_out_change_all_minio_io_path_to_minio
Change all minio-io path to minio
2015-05-11 16:31:10 -07:00
Harshavardhana 8d06504068 Change all minio-io path to minio 2015-05-11 16:23:10 -07:00
Harshavardhana e39de4f603 Fix typo introduced in previous commit 2015-05-11 14:24:31 -07:00
Harshavardhana a972e2c3d6 Merge pull request #590 from harshavardhana/pr_out_remove_signaturev2_support_bring_in_signaturev4_header_only_validation_for_now 2015-05-11 14:07:07 -07:00
Harshavardhana f45635524f Remove SignatureV2 support, bring in SignatureV4 header only validation for now 2015-05-11 13:38:40 -07:00
Harshavardhana 01c1bd6fc5 Merge pull request #589 from harshavardhana/pr_out_use_convenience_functions_for_url_values_over_looping_through_keys_fix_a_bug_in_listobjectparts_ 2015-05-10 11:38:02 -07:00
Harshavardhana b48b7f51ef Use convenience functions for url.Values over looping through keys, fix a bug in listObjectParts() 2015-05-10 11:32:41 -07:00
Harshavardhana 62f20c0f79 Merge pull request #588 from harshavardhana/pr_out_handle_partnumbermarker_with_listobjectparts_now_and_other_fixes 2015-05-09 19:41:25 -07:00
Harshavardhana 14b5828505 Handle partNumberMarker with listObjectParts now and other fixes 2015-05-09 19:39:00 -07:00
Frederick F. Kautz IV 729447794a Merge pull request #587 from fkautz/pr_out_limiting_upload_id_size 2015-05-09 18:31:09 -07:00
Frederick F. Kautz IV cf559fa48e Limiting upload id size 2015-05-09 18:28:50 -07:00
Frederick F. Kautz IV 55bda21881 Merge pull request #586 from fkautz/pr_out_adding_support_for_memory_driver_test 2015-05-09 18:28:45 -07:00
Frederick F. Kautz IV 61a9ea0f4b Adding support for memory driver test 2015-05-09 18:15:27 -07:00
Frederick F. Kautz IV cfe425e948 Merge pull request #585 from fkautz/pr_out_adding_tests_and_fixes_for_multipart_uploads_uncovered_from_tests 2015-05-09 17:44:25 -07:00
Frederick F. Kautz IV 058604aa21 Adding tests and fixes for multipart uploads uncovered from tests 2015-05-09 17:42:14 -07:00
Harshavardhana 0c54f99674 Merge pull request #584 from harshavardhana/pr_out_implement_abortmultipart 2015-05-09 16:12:17 -07:00
Harshavardhana 8860aa0c8c Implement AbortMultipart 2015-05-09 16:09:50 -07:00
Harshavardhana 9d407f6ee1 Merge pull request #583 from harshavardhana/pr_out_add_listparts_support_wip_do_not_merge 2015-05-09 13:59:35 -07:00
Harshavardhana 18c7f620cc Add listparts support 2015-05-09 13:55:55 -07:00
Harshavardhana ef793dcf03 Merge pull request #582 from harshavardhana/pr_out_handle_two_different_styles_of_time_format_s3cmd_now_compatible 2015-05-08 16:33:34 -07:00
Harshavardhana 04e388d620 Handle two different styles of time format, s3cmd now compatible 2015-05-08 16:01:59 -07:00
Harshavardhana aaf205b1fe Merge pull request #581 from harshavardhana/pr_out_move_expiration_code_into_its_own_and_add_ticker_select_case 2015-05-08 13:00:16 -07:00
Harshavardhana 01b474fca3 Move expiration code into its own and add ticker select case 2015-05-08 12:37:49 -07:00
Harshavardhana 8a65b90783 Merge pull request #580 from harshavardhana/pr_out_verify_incoming_md5sum_for_invidual_parts_in_complete_multipart_request_and_some_simplification_of_the_code 2015-05-08 04:01:37 -07:00
Harshavardhana 23a545673d Verify incoming md5sum for invidual parts in complete multipart request and some simplification of the code
Add two new functions for session cleanup
2015-05-08 03:59:05 -07:00
Harshavardhana a16a10afa9 Merge pull request #579 from harshavardhana/pr_out_re_enable_bucket_deletion_this_time_with_uploadid_sitting_there 2015-05-08 02:31:40 -07:00
Harshavardhana 616241a2c1 Re-enable bucket deletion, this time with uploadID sitting there 2015-05-08 02:28:38 -07:00
Harshavardhana 2ea10c798b Implement proper errors for Multipart 2015-05-08 02:02:51 -07:00
Harshavardhana 39e0875699 Merge pull request #578 from harshavardhana/pr_out_now_objectstorage_go_works_properly_with_multipart_upload
Now objectstorage-go works properly with Multipart upload.
2015-05-07 23:03:18 -07:00
Harshavardhana 82c3656f79 Reply back CompleteMultipartUploadResult properly with final ETag computed
- Now s3 libraries and also objectstorage-go work properly
2015-05-07 23:01:20 -07:00
Harshavardhana 5a372f4dd7 Merge pull request #577 from fkautz/pr_out_router_should_work_with_uploads_unescaped_now 2015-05-07 21:43:28 -07:00
Frederick F. Kautz IV ae5c99d7bb Router should work with ?uploads unescaped now 2015-05-07 21:37:34 -07:00
Frederick F. Kautz IV 9dc7b82b39 Merge pull request #576 from fkautz/pr_out_adding_multipart_support 2015-05-07 20:00:20 -07:00
Frederick F. Kautz IV 0266ec4bf6 Merge pull request #575 from fkautz/pr_out_fixing_panic_in_intelligent_attempted_to_delete_nonexistent_key 2015-05-07 19:55:56 -07:00
Frederick F. Kautz IV f050d5e974 Adding multipart support 2015-05-07 19:55:30 -07:00
Frederick F. Kautz IV ed71c28c37 Fixing panic in intelligent, attempted to delete nonexistent key 2015-05-07 19:12:49 -07:00
Frederick F. Kautz IV a4b4e9c148 Merge pull request #574 from fkautz/pr_out_adding_feature_flags 2015-05-07 13:59:23 -07:00
Frederick F. Kautz IV d0c4334834 Adding feature flags 2015-05-07 13:56:54 -07:00
Harshavardhana f1dbdbd234 Merge pull request #573 from harshavardhana/pr_out_get_rid_of_sub_domain_code_and_some_other_formatting_changes 2015-05-07 00:23:14 -07:00
Harshavardhana 1df28f3060 Get rid of sub-domain code and some other formatting changes 2015-05-07 00:21:40 -07:00
Harshavardhana 8c5a83ddcf Merge pull request #572 from harshavardhana/pr_out_add_marker_support_for_donut_also_add_a_testing_code 2015-05-05 22:20:18 -07:00
Harshavardhana 6d3d92694f Add Marker support for donut, also add a testing code 2015-05-05 22:18:24 -07:00
Harshavardhana 142f9263e1 Merge pull request #571 from harshavardhana/pr_out_add_lexicographic_marker_nextmarker_support_for_recursive_listing_of_objects_wip_do_not_merge 2015-05-05 18:12:18 -07:00
Harshavardhana 75028c2ad1 Add lexicographic Marker/NextMarker support for recursive listing of objects.
Also update times when an object is accessed logic
2015-05-05 18:05:34 -07:00
Frederick F. Kautz IV 7a87f89604 Merge pull request #570 from fkautz/pr_out_adding_xmlns 2015-05-05 13:32:31 -07:00
Frederick F. Kautz IV 24af2222c9 Adding xmlns 2015-05-05 12:54:34 -07:00
Harshavardhana 9d484719ae Merge pull request #568 from harshavardhana/pr_out_fix_a_potential_race_between_expireobjects_and_set_over_items_map 2015-05-04 22:38:59 -07:00
Harshavardhana 193a6606db Fix a potential race between ExpireObjects() and Set() over items map 2015-05-04 22:36:47 -07:00
Harshavardhana 3fc9b4554f Merge pull request #567 from harshavardhana/pr_out_convert_groupcache_lru_to_be_memory_size_based_rather_than_entry_based_calling_it_lru_memory
Convert groupcache lru to be memory size based rather than entry based calling it lru-memory
2015-05-04 22:04:26 -07:00
Harshavardhana ed1259d6f0 Deprecate LRU use just map[string]interface{} and call it intelligent 'cache' 2015-05-04 22:01:56 -07:00
Harshavardhana 63edb1e9a0 Nullify list memory to nil as we remove the element 2015-05-04 17:22:08 -07:00
Harshavardhana d63064b8af Optimize memory usage in GetPartialObject() for memory driver 2015-05-04 15:26:56 -07:00
Harshavardhana c8f31d97a8 Modify LRU further to add object expiration 2015-05-04 04:32:44 -07:00
Harshavardhana 670f997b07 Bring blockingWriter from client and use it here 2015-05-04 03:55:43 -07:00
Harshavardhana d0df548eb5 Use new LRU inside memory driver 2015-05-04 03:55:43 -07:00
Harshavardhana f7caef2d26 Change CreateObject() to take size argument from content-length 2015-05-04 03:55:43 -07:00
Harshavardhana c342ce1588 New LRU based on GroupCache which keeps track of memory rather than entries 2015-05-04 03:55:19 -07:00
Frederick F. Kautz IV 66e0fe23be Merge pull request #566 from fkautz/pr_out_deleting_key_from_lastaccessedobjects_on_eviction 2015-05-01 22:21:11 -07:00
Frederick F. Kautz IV 3cf045fd1b Deleting key from lastAccessedObjects on eviction 2015-05-01 22:01:07 -07:00
Frederick F. Kautz IV ad2037f446 Merge pull request #565 from fkautz/pr_out_removing_groupcache_lru_in_favor_of_imported_local_version 2015-05-01 21:02:17 -07:00
Frederick F. Kautz IV c80bbc86d5 Removing groupcache lru in favor of imported local version 2015-05-01 20:58:36 -07:00
Harshavardhana 600a75a786 Merge pull request #564 from harshavardhana/pr_out_rename_isvalidobject_to_isvalidobjectname_ 2015-05-01 20:33:05 -07:00
Harshavardhana 9ec8925f1c Rename IsValidObject() to IsValidObjectName() 2015-05-01 20:31:26 -07:00
Frederick F. Kautz IV 944d88c8ae Merge pull request #563 from fkautz/pr_out_fixing_documentation_issues_with_expire 2015-05-01 18:22:03 -07:00
Frederick F. Kautz IV ac595b1f2e Fixing documentation issues with expire 2015-05-01 18:20:22 -07:00
Frederick F. Kautz IV faaa647b0d Merge pull request #562 from fkautz/pr_out_reimagining_memory_settings_cli_input 2015-05-01 18:17:02 -07:00
Frederick F. Kautz IV 33ecba8e49 Reimagining memory settings cli input 2015-05-01 18:12:58 -07:00
Frederick F. Kautz IV b624072dbb Merge pull request #561 from fkautz/pr_out_attempt_to_fix_memory_lock_on_get_preventing_write 2015-05-01 17:52:24 -07:00
Frederick F. Kautz IV d158284cd5 Merge pull request #560 from fkautz/pr_out_removing_log_message_from_test 2015-05-01 17:47:43 -07:00
Frederick F. Kautz IV 25c268ac88 Attempt to fix memory lock on Get preventing write 2015-05-01 17:45:40 -07:00
Frederick F. Kautz IV 85f1b46492 Removing log message from test 2015-05-01 17:32:18 -07:00
Frederick F. Kautz IV 8e093eb6f6 Merge pull request #559 from fkautz/pr_out_fix_docker_support 2015-05-01 15:26:51 -07:00
Frederick F. Kautz IV 7cf86e6114 Fix docker support 2015-05-01 15:23:39 -07:00
Harshavardhana 1f3dd2374c Merge pull request #558 from harshavardhana/pr_out_even_mux_vars_don_t_help_handle_it_by_looking_at_req_url_path 2015-05-01 12:43:51 -07:00
Harshavardhana 2c7b30e5e1 Even mux vars don't help, handle it by looking at req.URL.Path 2015-05-01 12:41:17 -07:00
Frederick F. Kautz IV b69327a617 Merge pull request #556 from fkautz/pr_out_exposing_expiration_for_memory_driver 2015-04-30 21:28:12 -07:00
Frederick F. Kautz IV b86b26e7e5 Exposing expiration for memory driver 2015-04-30 21:20:54 -07:00
Harshavardhana c01fb92eca Merge pull request #557 from harshavardhana/pr_out_make_builddate_universal 2015-04-30 21:19:04 -07:00
Harshavardhana bbace9ac2e Make buildDate universal 2015-04-30 21:16:49 -07:00
Harshavardhana bbc32d6ac0 Disable domain based routing for now 2015-04-30 21:15:53 -07:00
Harshavardhana f3078d047c Get bucketName from mux.Vars instead of heuristic code, resolves subdomain issues 2015-04-30 21:11:32 -07:00
Frederick F. Kautz IV e911cc332e Merge pull request #554 from fkautz/pr_out_disable_eviction_on_0_expiration_time 2015-04-30 19:40:46 -07:00
Harshavardhana 9167312170 Merge pull request #555 from harshavardhana/pr_out_use_utc_everywhere 2015-04-30 19:40:37 -07:00
Harshavardhana 8e3d48bf35 Use UTC() everywhere
ref - https://github.com/golang/go/issues/1988, no standard function to set timeZone
2015-04-30 19:38:32 -07:00
Frederick F. Kautz IV 94e24f1a05 Disable eviction on 0 expiration time 2015-04-30 19:34:35 -07:00
Frederick F. Kautz IV b6d96335e7 Merge pull request #553 from fkautz/pr_out_setting_number_of_processors_to_use_to_max_available 2015-04-30 19:25:31 -07:00
Frederick F. Kautz IV f59535f052 Setting number of processors to use to max available 2015-04-30 19:23:07 -07:00
Harshavardhana 72395798c8 Merge pull request #552 from harshavardhana/pr_out_minio_config_directory_should_be_0700_not_os_modedir 2015-04-30 17:40:15 -07:00
Harshavardhana 2de81c8a3c Minio config directory should be 0700 not os.ModeDir 2015-04-30 15:42:49 -07:00
Frederick F. Kautz IV e76337d620 Merge pull request #551 from fkautz/pr_out_wrapping_functions_that_require_gc_so_that_references_are_released_before_running 2015-04-30 13:11:26 -07:00
Frederick F. Kautz IV 8e2f7f9493 Wrapping functions that require gc so that references are released before running 2015-04-30 12:38:12 -07:00
Harshavardhana 4ea186729a Merge pull request #550 from harshavardhana/pr_out_changes_to_createobject_now_returns_back_md5_along_with_any_error 2015-04-30 03:43:14 -07:00
Harshavardhana d815e6adfd Changes to CreateObject() now returns back md5 along with any error
- This change is necessary to avoid the racy calls to GetObjectMetadata()
- This change is also necessary since one has to reply back md5sum with
  PUT object response header
2015-04-30 03:38:14 -07:00
Harshavardhana 13cae94191 Merge pull request #545 from harshavardhana/pr_out_conn_limit_changes 2015-04-30 01:26:24 -07:00
Harshavardhana fd2203b1b7 Some more improvements to connection limit 2015-04-30 01:23:44 -07:00
Harshavardhana 58491d22fc Merge pull request #548 from harshavardhana/pr_out_memory_now_evicts_bucket_if_no_more_objects_in_memory_struct 2015-04-30 00:33:21 -07:00
Harshavardhana f8a16dd22b Memory now evicts bucket if no more objects in memory struct
- To avoid race in expiration while accessing memory driver structs with
  in two competing write locks. Use lru Len() instead to know exact length
  to schedule for eviction.

- squash both bucket and object structs, instead use a separate map to keep
  mutable info of lastAccessTime which can be independently used inside the
  expiration routine.
2015-04-30 00:31:52 -07:00
Frederick F. Kautz IV 63ba97fd8e Merge pull request #547 from fkautz/pr_out_removing_entity_too_large_errors_from_memory_driver 2015-04-30 00:12:01 -07:00
Frederick F. Kautz IV ed0a9a9e06 Removing entity too large errors from memory driver 2015-04-30 00:09:54 -07:00
Frederick F. Kautz IV 446a137904 Merge pull request #546 from fkautz/pr_out_adding_debug_statements_for_testing 2015-04-29 21:15:12 -07:00
Frederick F. Kautz IV aff2b3b06a Adding debug statements for testing 2015-04-29 21:13:32 -07:00
Frederick F. Kautz IV a521309b78 Merge pull request #542 from fkautz/pr_out_make_minio_work_with_curl_and_browsers_again 2015-04-29 20:21:38 -07:00
Frederick F. Kautz IV 82a16b8848 Make minio work with curl and browsers again 2015-04-29 20:17:26 -07:00
Frederick F. Kautz IV 73de05feb6 Merge pull request #544 from fkautz/pr_out_fixing_race_condition 2015-04-29 18:57:05 -07:00
Frederick F. Kautz IV 3a1386165f Fixing race condition 2015-04-29 18:54:59 -07:00
Harshavardhana 710e732cf0 Merge pull request #543 from harshavardhana/pr_out_fix_out_of_memory_issue 2015-04-29 18:50:19 -07:00
Harshavardhana 03bca9a001 Fix out of memory issue 2015-04-29 18:33:19 -07:00
Harshavardhana 50d871c2db Merge pull request #540 from harshavardhana/pr_out_remove_connection_limit_handle_throttling_outisde_in_iptables 2015-04-29 17:32:01 -07:00
Harshavardhana 25d4c0f6fa A small logical change in messaging and logging 2015-04-29 17:30:54 -07:00
Harshavardhana 8be3b92ab7 Merge pull request #541 from fkautz/pr_out_adding_error_message_on_connection_limit_met 2015-04-29 17:24:04 -07:00
Frederick F. Kautz IV f596c744ed Adding error message on connection limit met 2015-04-29 17:21:23 -07:00
Harshavardhana 8d1d309630 Merge pull request #539 from harshavardhana/pr_out_return_resources_as_its_available_not_a_new_value 2015-04-29 16:50:07 -07:00
Harshavardhana a89c4a57d3 Return resources as its available, not a new value 2015-04-29 16:47:14 -07:00
Harshavardhana edf838df74 Merge pull request #538 from harshavardhana/pr_out_bump_up_gocyclo_to_18 2015-04-29 15:34:56 -07:00
Harshavardhana a60d279817 bump up gocyclo to 18 2015-04-29 15:34:00 -07:00
Harshavardhana 251c99176a Merge pull request #537 from harshavardhana/pr_out_add_proper_content_length_for_error_and_success_responses 2015-04-29 15:32:12 -07:00
Frederick F. Kautz IV c718910300 Merge pull request #536 from fkautz/pr_out_expirations_are_now_based_on_last_accessed_instead_of_time_created 2015-04-29 15:30:54 -07:00
Frederick F. Kautz IV 0da04c6f17 Expirations are now based on last accessed instead of time created 2015-04-29 15:28:45 -07:00
Harshavardhana 92e4301414 Add proper content-length for error and success responses
- All compliance issues with S3 API for Put,Get,List (Bucket,Object) respectively
 - Encodes and returns back proper HTTP headers
2015-04-29 15:28:28 -07:00
Frederick F. Kautz IV c8db3e1c3b Merge pull request #535 from fkautz/pr_out_adding_lru 2015-04-29 15:26:01 -07:00
Frederick F. Kautz IV 5fc5f79ab7 Adding lru 2015-04-29 15:08:26 -07:00
Frederick F. Kautz IV b6daf99dcd Merge pull request #533 from fkautz/pr_out_simplifying_memory_sleep_logic 2015-04-29 13:55:24 -07:00
Frederick F. Kautz IV 8fcb697844 Simplifying memory sleep logic 2015-04-29 13:53:09 -07:00
Frederick F. Kautz IV 362305d898 Merge pull request #534 from fkautz/pr_out_experiment_running_gofmt_on_godeps 2015-04-29 13:33:08 -07:00
Frederick F. Kautz IV 9001d87d20 Experiment running gofmt on Godeps 2015-04-29 13:30:14 -07:00
Frederick F. Kautz IV 8689ec9a54 Merge pull request #532 from fkautz/pr_out_adding_expiration 2015-04-29 13:11:35 -07:00
Frederick F. Kautz IV 5cc9418ca7 Adding expiration 2015-04-29 13:02:21 -07:00
Frederick F. Kautz IV 2ab8988a41 Merge pull request #531 from fkautz/pr_out_api_logging_is_now_in_its_own_package 2015-04-29 12:40:27 -07:00
Frederick F. Kautz IV a608524ebf api logging is now in its own package 2015-04-29 12:24:53 -07:00
Harshavardhana 9a969ea59b Merge pull request #530 from harshavardhana/pr_out_collate_success_response_into_writesuccessresponse_add_docs 2015-04-29 10:58:37 -07:00
Harshavardhana d1d5f7a78d Collate success response into writeSuccessResponse(), add docs 2015-04-29 10:52:04 -07:00
Harshavardhana 45a0fb21fa Merge pull request #529 from harshavardhana/pr_out_maxobjectsize_and_minobjectsize_limitation_added_at_putobjecthandler_ 2015-04-29 02:23:34 -07:00
Harshavardhana b18bb230da maxObjectSize and minObjectSize limitation added at putObjectHandler()
Put() replies back with

   - EntityTooLarge with > 5GB in single PUT operation
   - EntityTooSmall with < 1B in single PUT operation
   - IncompleteBody with ho Content-Length found in HTTP request header
2015-04-29 02:19:53 -07:00
Anand Babu (AB) Periasamy c14496f928 Merge pull request #528 from abperiasamy/clean-clean
cleaning make:clean
2015-04-28 21:29:37 -07:00
Harshavardhana b01fc9d125 Merge pull request #527 from harshavardhana/pr_out_add_minio_cli_changes_and_add_customapphelptemplate 2015-04-28 21:26:26 -07:00
Anand Babu (AB) Periasamy b8eb34aded cleaning make:clean 2015-04-28 21:24:59 -07:00
Harshavardhana 76701187e3 Add minio cli changes and add CustomAppHelpTemplate 2015-04-28 21:24:56 -07:00
Anand Babu (AB) Periasamy a3d03184ca Merge pull request #526 from abperiasamy/messages
print using console functions
2015-04-28 21:15:32 -07:00
Anand Babu (AB) Periasamy 43e9cb203d print using console functions 2015-04-28 21:12:23 -07:00
Frederick F. Kautz IV b0a4d07736 Merge pull request #525 from fkautz/pr_out_adding_initial_logging_framework_to_api_router 2015-04-28 20:44:39 -07:00
Frederick F. Kautz IV 172cd18455 Adding initial logging framework to api_router 2015-04-28 20:37:08 -07:00
Frederick F. Kautz IV e7f2fc9e4e Merge pull request #524 from fkautz/pr_out_adding_json_logging_to_stderr 2015-04-28 18:15:18 -07:00
Frederick F. Kautz IV 88cca647ea Adding json logging to stderr 2015-04-28 18:11:53 -07:00
Frederick F. Kautz IV 83cd299b23 Merge pull request #523 from fkautz/pr_out_setting_gimme_to_use_go1_4_2 2015-04-28 12:36:16 -07:00
Frederick F. Kautz IV 926b1e81e7 Setting gimme to use go1.4.2 2015-04-28 12:35:49 -07:00
Frederick F. Kautz IV b1b6fd5da9 Merge pull request #521 from fkautz/pr_out_removing_quotas_will_handle_with_iptables 2015-04-28 12:29:20 -07:00
Frederick F. Kautz IV b8ea1c234b Setting gimme to use go1.4.2 2015-04-28 12:22:12 -07:00
Frederick F. Kautz IV de091068e8 Removing quotas, will handle with iptables 2015-04-28 12:14:34 -07:00
Anand Babu (AB) Periasamy 6c0d95a98c Merge pull request #522 from abperiasamy/console
simple console
2015-04-27 22:03:25 -07:00
Anand Babu (AB) Periasamy 5127dfb4fc simple console 2015-04-27 22:01:07 -07:00
Frederick F. Kautz IV f22390ccef Merge pull request #520 from fkautz/pr_out_updating_godep_deps 2015-04-27 21:11:42 -07:00
Frederick F. Kautz IV adaa0e1821 Merge pull request #519 from fkautz/pr_out_removing_short_flags 2015-04-27 21:11:23 -07:00
Frederick F. Kautz IV 0cca734bc9 Updating godep deps 2015-04-27 21:02:36 -07:00
Frederick F. Kautz IV fc59401ac5 Removing short flags 2015-04-27 20:20:03 -07:00
Frederick F. Kautz IV 2fcaa63db0 Revert "remove single char args"
This reverts commit 1e307d2888.
2015-04-27 20:18:43 -07:00
Frederick F. Kautz IV 2c3329a519 Merge pull request #518 from fkautz/pr_out_critical_sections_are_now_protected_by_lock 2015-04-27 20:01:51 -07:00
Frederick F. Kautz IV f2257a643c Critical sections are now protected by lock 2015-04-27 19:59:58 -07:00
Harshavardhana b85595addf Merge pull request #516 from harshavardhana/pr_out_add_some_logging_with_debug 2015-04-27 19:44:34 -07:00
Anand Babu (AB) Periasamy e9b146c1d8 Merge pull request #517 from abperiasamy/janitor-is-back
remove single char args
2015-04-27 19:34:37 -07:00
Anand Babu (AB) Periasamy 1e307d2888 remove single char args 2015-04-27 19:30:44 -07:00
Harshavardhana 605edbc307 Add some logging with debug 2015-04-27 19:26:24 -07:00
Harshavardhana 7bdcf4bbf3 Merge pull request #515 from fkautz/pr_out_fix_multiple_response_writeheader_calls
Fix multiple response.WriteHeader calls
2015-04-27 19:21:47 -07:00
Frederick F. Kautz IV db5870be28 Fix multiple response.WriteHeader calls 2015-04-27 18:30:21 -07:00
Harshavardhana 7e72cefd74 Merge pull request #514 from harshavardhana/pr_out_fix_build_date_typo 2015-04-27 16:08:23 -07:00
Harshavardhana 740e12e81d Fix build date typo 2015-04-27 16:08:11 -07:00
Frederick F. Kautz IV fc2537eef9 Merge pull request #513 from fkautz/pr_out_adding_software_fallback 2015-04-27 14:41:41 -07:00
Frederick F. Kautz IV 289c859675 Adding software fallback 2015-04-27 13:55:40 -07:00
Harshavardhana 943192f684 Merge pull request #512 from harshavardhana/pr_out_add_build_date_using_ldflags 2015-04-27 13:11:12 -07:00
Harshavardhana 096a994c7b Add build date using ldflags 2015-04-27 13:08:51 -07:00
Harshavardhana 66747399fd Merge pull request #511 from harshavardhana/pr_out_verify_if_request_date_is_5minutes_late_reject_such_a_request_as_it_could_be_a_possible_replay_attack 2015-04-27 03:58:17 -07:00
Harshavardhana ade803a923 Verify if request date is 5minutes late, reject such a request as
it could be a possible replay attack.

This commit also fixes #505, by returning MethodNotAllowed instead of NotImplemented
2015-04-27 03:55:10 -07:00
Harshavardhana 1531802b73 Merge pull request #510 from harshavardhana/pr_out_now_client_requests_for_acl_changes_are_honored_through_putbucketacl_api 2015-04-27 03:06:12 -07:00
Harshavardhana 9232ce3b4e Now client requests for ACL changes are honored through PutBucketACL API 2015-04-27 03:04:29 -07:00
Harshavardhana 1b411f9e86 Merge pull request #509 from harshavardhana/pr_out_now_donut_supports_bucket_acl_s_bringing_in_this_support_for_dl_minio_io 2015-04-27 02:11:49 -07:00
Harshavardhana c99d96dbc2 Now donut supports bucket ACL's, bringing in this support for dl.minio.io 2015-04-27 02:09:32 -07:00
Harshavardhana f5a51ae1bb Merge pull request #507 from harshavardhana/pr_out_limit_memory_at_100_buckets_and_return_error_appropriately 2015-04-26 22:17:03 -07:00
Harshavardhana 8beca83090 Limit memory mode at 100 buckets and return error appropriately
~~~
mc: <ERROR> Failed to create bucket for URL [http://localhost:9000/newbucket-101]. Reason: [You have attempted to create more buckets than allowed.].
~~~

Response from server
2015-04-26 22:15:39 -07:00
Harshavardhana f20515b4ed Merge pull request #506 from harshavardhana/pr_out_enhance_error_responses_for_request_limit_and_bring_some_code_from_api_errors 2015-04-26 22:12:21 -07:00
Harshavardhana 2d96d5ad57 Enhance error responses for request limit and bring some code from api errors
~~~
mc: <ERROR> Failed to create bucket for URL [http://localhost:9000/newbucket-101]. Reason: [Reduce your request rate.].
~~~

Client sees proper errors now.
2015-04-26 22:10:59 -07:00
Frederick F. Kautz IV 8a57006b36 Merge pull request #504 from fkautz/pr_out_making_lock_much_less_aggressive_fixes_multiple_uploads_blocking 2015-04-26 20:11:50 -07:00
Frederick F. Kautz IV e2807a167f Merge pull request #503 from fkautz/pr_out_bandwidth_quota_now_supports_100_continue 2015-04-26 20:09:13 -07:00
Frederick F. Kautz IV a974e4d7c7 Making lock much less aggressive, fixes multiple uploads blocking 2015-04-26 20:08:37 -07:00
Frederick F. Kautz IV 258bf55e31 Bandwidth quota now supports 100-Continue 2015-04-26 20:07:05 -07:00
Frederick F. Kautz IV 9431a54a27 finish me 2015-04-26 19:25:48 -07:00
Frederick F. Kautz IV d11803b125 Merge pull request #502 from fkautz/pr_out_revert_exporting_writeerrorresponse 2015-04-26 17:04:28 -07:00
Frederick F. Kautz IV 202fc26719 Revert "Exporting WriteErrorResponse"
This reverts commit e05d46a0b5.
2015-04-26 17:02:49 -07:00
Frederick F. Kautz IV c29677b245 Merge pull request #501 from fkautz/pr_out_exporting_writeerrorresponse 2015-04-26 16:30:45 -07:00
Frederick F. Kautz IV e05d46a0b5 Exporting WriteErrorResponse 2015-04-26 16:28:54 -07:00
Frederick F. Kautz IV 3fb4f2894d Merge pull request #500 from fkautz/pr_out_adding_connection_limits 2015-04-26 16:28:50 -07:00
Frederick F. Kautz IV 64f7d04cd1 Adding connection limits 2015-04-26 16:14:51 -07:00
Frederick F. Kautz IV e68e0c28f7 Merge pull request #499 from fkautz/pr_out_bandwidth_quotas_now_work_on_data_returned_from_server 2015-04-26 15:51:38 -07:00
Frederick F. Kautz IV 7867ee89fa Bandwidth quotas now work on data returned from server 2015-04-26 15:49:55 -07:00
Harshavardhana 5fe173edf1 Merge pull request #498 from harshavardhana/pr_out_bring_in_changes_from_minio_io_cli_properly_
Bring in changes from minio-io/cli properly :-)
2015-04-26 15:43:29 -07:00
Harshavardhana f7d2711d60 Merge pull request #494 from abperiasamy/md5sum-path-bug
Version is now based on MD5SUM of its binary
2015-04-26 15:42:48 -07:00
Harshavardhana 6332a8d108 Bring in changes from minio-io/cli properly :-) 2015-04-26 15:41:32 -07:00
Harshavardhana 9bc0f61191 Merge pull request #497 from minio-io/revert-496-pr_out_bring_in_changes_from_minio_io_cli
Revert "Bring in changes from minio-io/cli"
2015-04-26 15:39:47 -07:00
Harshavardhana d7a8f5a5a4 Revert "Bring in changes from minio-io/cli" 2015-04-26 15:39:26 -07:00
Harshavardhana 40c26cf9a3 Merge pull request #496 from harshavardhana/pr_out_bring_in_changes_from_minio_io_cli 2015-04-26 15:36:24 -07:00
root c2d8053787 Bring in changes from minio-io/cli 2015-04-26 15:34:13 -07:00
Frederick F. Kautz IV a3af3514ca Merge pull request #495 from fkautz/pr_out_quotas_are_more_accurate_occur_on_read_ 2015-04-26 15:13:15 -07:00
Frederick F. Kautz IV e2403cbc56 Quotas are more accurate, occur on Read() 2015-04-26 15:07:57 -07:00
Anand Babu (AB) Periasamy 0d97a98594 Version is now based on MD5SUM of its binary 2015-04-26 02:58:10 -07:00
Frederick F. Kautz IV f94d9db4f7 Merge pull request #493 from fkautz/pr_out_switching_back_to_bigendian 2015-04-25 18:18:02 -07:00
Frederick F. Kautz IV bbb493080f Switching back to BigEndian 2015-04-25 18:16:21 -07:00
Frederick F. Kautz IV 6ac5fb78d8 Merge pull request #492 from fkautz/pr_out_adding_quotas_based_upon_type 2015-04-25 18:08:36 -07:00
Frederick F. Kautz IV 3a48f9fe4d Adding quotas based upon type 2015-04-25 18:07:02 -07:00
Harshavardhana 5a2fb9741a Merge pull request #491 from harshavardhana/pr_out_use_standard_functions_to_achieve_byteorder_converstion 2015-04-25 17:08:49 -07:00
Harshavardhana b75f46aaa0 Use standard functions to achieve byteorder converstion 2015-04-25 13:18:15 -07:00
Anand Babu (AB) Periasamy 2eb1b8ad76 Merge pull request #490 from abperiasamy/hashbin
Version is now based on MD5SUM of its binary
2015-04-24 21:55:29 -07:00
Anand Babu (AB) Periasamy b010fd0ff3 Version is now based on MD5SUM of its binary 2015-04-24 21:51:52 -07:00
Frederick F. Kautz IV 5b0591ffad Merge pull request #489 from fkautz/pr_out_quota_handlers_now_log_against_ip_properly_against_a_duration 2015-04-24 20:53:26 -07:00
Frederick F. Kautz IV e2475925ea quota handlers now log against ip properly against a duration 2015-04-24 20:49:33 -07:00
Harshavardhana b3a9d8b058 Merge pull request #483 from harshavardhana/pr_out_memory_now_handles_submitting_large_files_fixes_482 2015-04-24 15:25:38 -07:00
Harshavardhana c5d8ca245d Memory now handles submitting large files - fixes #482 2015-04-24 15:22:22 -07:00
Frederick F. Kautz IV 4b45b82711 Merge pull request #481 from fkautz/pr_out_add_initial_framework_for_quota 2015-04-24 00:19:25 -07:00
Frederick F. Kautz IV fda50d52c8 Add initial framework for quota 2015-04-24 00:16:29 -07:00
Frederick F. Kautz IV b3f51d53c4 Merge pull request #480 from fkautz/pr_out_moving_factories_and_start_minio_method_to_server_package 2015-04-23 16:15:55 -07:00
Frederick F. Kautz IV 5a607a6762 Moving factories and start minio method to server package 2015-04-23 16:13:50 -07:00
Frederick F. Kautz IV c75b9d58f5 Merge pull request #479 from fkautz/pr_out_simplifying_server_config_handling 2015-04-23 16:13:39 -07:00
Frederick F. Kautz IV 5c515d3138 Simplifying server config handling 2015-04-23 12:44:22 -07:00
Harshavardhana a216bf836a Merge pull request #478 from harshavardhana/pr_out_donut_mode_will_now_take_multiple_paths_as_argument_updated_docs_as_well 2015-04-23 11:38:31 -07:00
Harshavardhana 5ae8d34f76 Donut mode will now take multiple paths as argument, updated docs as well 2015-04-23 11:36:14 -07:00
Harshavardhana 7c17a60d1f Merge pull request #477 from harshavardhana/pr_out_update_command_docs_further 2015-04-23 03:37:05 -07:00
Harshavardhana c7be1a1355 Update command docs further 2015-04-23 03:34:20 -07:00
Harshavardhana d447ca9af1 Merge pull request #476 from harshavardhana/pr_out_disable_verifying_acl_until_we_get_webcli_up_and_running 2015-04-23 03:24:55 -07:00
Harshavardhana a5729e8c02 Disable verifying ACL until we get webcli up and running 2015-04-23 03:21:08 -07:00
Harshavardhana 5ddd624a95 Merge pull request #475 from harshavardhana/pr_out_add_proper_help_and_several_other_cleanup 2015-04-23 02:47:49 -07:00
Harshavardhana bcc4449de7 Add proper help and several other cleanup 2015-04-23 02:42:50 -07:00
Harshavardhana b153834d4d Merge pull request #474 from harshavardhana/pr_out_finishing_all_the_test_case_support_for_acl_and_other_fixes 2015-04-23 01:27:26 -07:00
Harshavardhana e95604ff86 Finishing all the test case support for ACL and other fixes 2015-04-23 01:24:46 -07:00
Frederick F. Kautz IV de710962c0 Merge pull request #473 from fkautz/pr_out_refactoring_cli_to_take_commands 2015-04-23 01:10:18 -07:00
Frederick F. Kautz IV 0f8626ab1a Refactoring cli to take commands 2015-04-23 01:05:44 -07:00
Harshavardhana 4ed03881ff Merge pull request #472 from harshavardhana/pr_out_further_fixes_for_acl_support_currently_code_is_disabled_in_all_the_handlers
Further fixes for ACL support, currently code is disabled in all the handlers
2015-04-22 19:35:07 -07:00
Harshavardhana 848c4ee31c Further fixes for ACL support, currently code is disabled in all the handlers
Disabled because due to lack of testing support. Once we get that in we can
uncomment them back.
2015-04-22 19:31:45 -07:00
Harshavardhana 1c0ff2c758 ACL driver/storage layer support 2015-04-22 19:31:45 -07:00
Harshavardhana c8713fd650 Bring in full fledged acl support 2015-04-22 18:26:35 -07:00
Harshavardhana 2c1455af1b Implement x-amz-acl tests 2015-04-22 18:26:35 -07:00
Harshavardhana 107e077ec0 Implement x-amz-acl handling 2015-04-22 18:26:35 -07:00
Frederick F. Kautz IV 28785421cd Merge pull request #471 from fkautz/pr_out_memory_driver_now_limits_by_size 2015-04-22 18:26:28 -07:00
Frederick F. Kautz IV c56f7380d6 Memory driver now limits by size 2015-04-22 17:50:26 -07:00
Harshavardhana 276c02af62 Merge pull request #470 from harshavardhana/pr_out_remove_bucketpolicy_handlers_and_all_references 2015-04-22 14:49:36 -07:00
Harshavardhana b121c8588f Remove bucketpolicy handlers and all its references 2015-04-22 14:46:51 -07:00
Harshavardhana ed67a1269d Merge pull request #469 from harshavardhana/pr_out_file_driver_to_take_the_high_road 2015-04-16 02:21:44 -07:00
Harshavardhana 3f33643d39 File driver to take the high road 2015-04-16 02:16:39 -07:00
Frederick F. Kautz IV 7d01300d82 Merge pull request #468 from fkautz/pr_out_adding_lru_to_memory_driver_not_wired_to_command_line_opts 2015-04-15 12:58:30 -07:00
Frederick F. Kautz IV 59a81a73c6 Adding lru to memory driver, not wired to command line opts 2015-04-15 12:49:41 -07:00
Frederick F. Kautz IV b464ddbf31 Merge pull request #467 from fkautz/pr_out_better_locking_in_memory_driver 2015-04-15 12:13:38 -07:00
Frederick F. Kautz IV 0cab3fd151 Better locking in memory driver 2015-04-15 11:48:56 -07:00
Frederick F. Kautz IV e9930c49db Merge pull request #466 from fkautz/pr_out_adding_slack_notifications 2015-04-12 11:48:11 -07:00
Frederick F. Kautz IV a5b0547c1a Adding slack notifications 2015-04-12 11:45:43 -07:00
Harshavardhana c566b8dabd Update README.md 2015-04-11 18:12:19 -07:00
Harshavardhana 9dd97b823d Merge pull request #465 from harshavardhana/pr_out_adding_travis_and_godoc_badge 2015-04-11 18:10:24 -07:00
Harshavardhana f6964b5753 Adding travis and godoc badge 2015-04-11 18:10:02 -07:00
Frederick F. Kautz IV 77060fec44 Merge pull request #463 from fkautz/pr_out_adding_travis_yml_to_minio
Adding travis.yml to minio
2015-04-11 17:52:06 -07:00
Frederick F. Kautz IV bcbf1a2390 Adding travis.yml to minio 2015-04-11 17:49:50 -07:00
Harshavardhana 87e4755282 Merge pull request #464 from harshavardhana/pr_out_fix_build_for_travis 2015-04-11 17:31:37 -07:00
Harshavardhana 97d1f03a87 Fix build for travis 2015-04-11 17:31:01 -07:00
Harshavardhana 0128481f45 Merge pull request #462 from harshavardhana/pr_out_remove_docs_minimal_docs_going_to_be_at_minio_io_instead_and_rest_amazon_docs 2015-04-10 21:22:34 -07:00
Harshavardhana c63bdf79fa Remove docs, minimal docs going to be at minio.io instead and rest amazon docs 2015-04-10 21:21:59 -07:00
Harshavardhana 74506bb48b Merge pull request #461 from harshavardhana/pr_out_fix_golint_complaint 2015-04-08 23:43:43 -07:00
Harshavardhana 148935392d Fix golint complaint 2015-04-08 23:42:59 -07:00
Frederick F. Kautz IV b2d54f323b Merge pull request #460 from fkautz/pr_out_removing_unneeded_files 2015-04-08 20:58:53 -07:00
Frederick F. Kautz IV 26d8deee40 Removing unneeded files 2015-04-08 20:58:42 -07:00
Frederick F. Kautz IV 1d4bc0c34e Merge pull request #459 from fkautz/pr_out_adding_comments_to_iodine 2015-04-08 19:44:52 -07:00
Frederick F. Kautz IV 7212b3406a Adding comments to iodine 2015-04-08 19:44:44 -07:00
Frederick F. Kautz IV 0e89facf7d Merge pull request #458 from fkautz/pr_out_adding_iodine_error_conversion 2015-04-08 19:32:48 -07:00
Frederick F. Kautz IV c12d5ea8a9 Adding iodine error conversion 2015-04-08 19:32:37 -07:00
Harshavardhana e2c54a0904 Merge pull request #457 from harshavardhana/pr_out_iodine_is_part_of_minio_now 2015-04-08 18:14:48 -07:00
Harshavardhana 38155e86ac iodine is part of minio now 2015-04-08 18:05:48 -07:00
Harshavardhana 879e428596 Merge pull request #456 from harshavardhana/pr_out_add_everything_back_into_one_project_hood_still_missing_iodine 2015-04-08 17:56:14 -07:00
Harshavardhana 7fd1cc073c Add everything back into one project hood, still missing iodine 2015-04-08 17:47:56 -07:00
Frederick F. Kautz IV 60b30bdd0a Merge pull request #455 from fkautz/pr_out_moving_object_storage_drivers_back_to_minio 2015-04-08 16:28:30 -07:00
Frederick F. Kautz IV 6241c9880b Moving object storage drivers back to minio 2015-04-08 16:28:14 -07:00
Harshavardhana d3caf2b733 Merge pull request #454 from harshavardhana/pr_out_update_minio_io_donut_minio_io_objectdriver 2015-04-07 16:20:30 -07:00
Harshavardhana ec39155089 Update minio-io/donut, minio-io/objectdriver 2015-04-07 16:14:44 -07:00
Harshavardhana 34d06101cc Merge pull request #453 from harshavardhana/pr_out_implement_headbuckethandler_and_its_related_tests 2015-04-07 01:17:24 -07:00
Harshavardhana 2a21b7d639 Implement headBucketHandler() and its related tests
Remove internal testify/mock and use upstream - update all godeps
2015-04-07 01:16:32 -07:00
Harshavardhana 2ddde59b46 Merge pull request #452 from harshavardhana/pr_out_merge_new_changes_from_minio_io_donut_minio_io_objectdriver 2015-04-07 00:01:32 -07:00
Harshavardhana b63c7fd84f Merge new changes from minio-io/donut; minio-io/objectdriver 2015-04-07 00:01:19 -07:00
Harshavardhana 35b8bb368d Merge pull request #451 from harshavardhana/pr_out_pull_in_new_changes_from_minio_io_objectdriver_and_minio_io_donut 2015-04-06 22:29:23 -07:00
Harshavardhana 649f1104dd Pull in new changes from minio-io/objectdriver and minio-io/donut 2015-04-06 22:29:10 -07:00
Harshavardhana 81e2dafe36 Merge pull request #450 from harshavardhana/pr_out_update_to_new_changes_at_minio_io_objectdriver_and_minio_io_donut 2015-04-06 21:45:30 -07:00
Harshavardhana b93b6785c2 Update to new changes at minio-io/objectdriver and minio-io/donut
New ObjectStorage interface is now fully written and working as
expected.
2015-04-06 21:44:32 -07:00
Frederick F. Kautz IV 81e4a3332c Merge pull request #449 from fkautz/pr_out_updating_to_use_objectdriver 2015-04-06 18:00:44 -07:00
Frederick F. Kautz IV ea961ef16d Updating to use objectdriver 2015-04-06 18:00:18 -07:00
Frederick F. Kautz IV 1ebc692ea2 Merge pull request #447 from fkautz/pr_out_adding_debug_logger_to_log_package 2015-04-06 12:15:39 -07:00
Frederick F. Kautz IV e71cc8d833 Adding Debug logger to log package 2015-04-06 12:15:19 -07:00
Harshavardhana 70c6258440 Merge pull request #446 from harshavardhana/pr_out_erasure_is_now_external_pull_it_and_update_from_minio_io_erasure 2015-04-05 23:53:19 -07:00
Harshavardhana 319feb52f1 erasure is now external pull it and update from minio-io/erasure 2015-04-05 23:51:24 -07:00
Frederick F. Kautz IV 603b851226 Merge pull request #445 from fkautz/pr_out_fix_fd_leak 2015-04-05 21:34:07 -07:00
Frederick F. Kautz IV 052817ff91 Fix fd leak 2015-04-05 21:33:24 -07:00
Harshavardhana 2452393088 Merge pull request #444 from harshavardhana/pr_out_return_proper_return_for_all_drivers_when_bucketnotfound 2015-04-05 15:56:06 -07:00
Harshavardhana d324c4b061 Return proper return for all drivers when BucketNotFound 2015-04-05 15:55:10 -07:00
Harshavardhana 0475d7d056 Migrate to external Donut package 2015-04-05 14:59:24 -07:00
Frederick F. Kautz IV 183df976f3 Merge pull request #443 from fkautz/pr_out_reformatting_imports 2015-04-04 14:00:34 -07:00
Frederick F. Kautz IV 2f44438843 Reformatting imports 2015-04-04 13:59:59 -07:00
Frederick F. Kautz IV 55a6d1797f Merge pull request #442 from fkautz/pr_out_replacing_gopkg_in_check_v1_with_minio_io_check 2015-04-04 13:38:10 -07:00
Frederick F. Kautz IV be4bc44b4d Replacing gopkg.in/check.v1 with minio-io/check 2015-04-04 13:37:30 -07:00
Frederick F. Kautz IV e6abca1a63 Adding iodine to object HEAD verb 2015-04-04 12:46:34 -07:00
Frederick F. Kautz IV 8198259dda Merge pull request #441 from fkautz/pr_out_updating_godeps_json 2015-04-03 20:45:24 -07:00
Frederick F. Kautz IV 54a5e80ea5 Updating Godeps.json 2015-04-03 20:45:17 -07:00
Frederick F. Kautz IV 2abb4bba3a Merge pull request #440 from fkautz/pr_out_removing_godeps_from_pkg_api 2015-04-03 20:40:37 -07:00
Frederick F. Kautz IV 46badca07e Removing Godeps from pkg/api 2015-04-03 20:40:21 -07:00
Frederick F. Kautz IV 6ce3133f1e Merge pull request #439 from fkautz/pr_out_adding_test_for_invalid_range_in_api 2015-04-03 20:39:43 -07:00
Frederick F. Kautz IV 4171ad8b69 Adding test for invalid range in api 2015-04-03 20:35:39 -07:00
Harshavardhana 9e5911cc62 Merge pull request #438 from harshavardhana/pr_out_remove_mxj_update_gopkg_in_check_v1 2015-04-03 19:04:00 -07:00
Harshavardhana 717913bc8a Remove mxj, Update gopkg.in/check.v1 2015-04-03 19:03:16 -07:00
Harshavardhana 4079dd1d12 Commit testify,objx, gorilla/mux, minio-io/erasure gopkg.in/check.v1 2015-04-03 18:57:47 -07:00
Harshavardhana 4b25d4e8db Use verifyError instead of parsResponse, also get rid of mxj dependency 2015-04-03 18:56:47 -07:00
Frederick F. Kautz IV 321a1a2d36 Merge pull request #437 from fkautz/pr_out_better_error_handling_tests_for_get_object 2015-04-03 18:53:50 -07:00
Frederick F. Kautz IV 9954e5c280 Better error handling + tests for get object 2015-04-03 18:53:27 -07:00
Frederick F. Kautz IV 407251d51f Merge pull request #436 from fkautz/pr_out_adding_tests_for_put_bucket_errors_fixed_mismatching_error 2015-04-03 18:38:05 -07:00
Frederick F. Kautz IV db1e6e5988 Adding tests for put bucket errors, fixed mismatching error 2015-04-03 18:37:39 -07:00
Frederick F. Kautz IV a6fc618f91 Merge pull request #435 from fkautz/pr_out_adding_iodine_and_tests_for_for_list_buckets_errors 2015-04-03 18:29:39 -07:00
Frederick F. Kautz IV ebf1e784b3 Adding iodine and tests for for list buckets errors 2015-04-03 18:29:31 -07:00
Frederick F. Kautz IV 37c601c21c Merge pull request #434 from fkautz/pr_out_adding_better_error_support_to_api 2015-04-03 18:06:43 -07:00
Frederick F. Kautz IV 5865295f5d Adding better error support to api 2015-04-03 18:06:30 -07:00
Harshavardhana a29990e4bc Merge pull request #433 from harshavardhana/pr_out_add_full_rebuild_for_minio_command_to_avoid_godep_stale_issues 2015-04-02 16:12:17 -07:00
Harshavardhana 637d2d687a Add full rebuild for minio command to avoid godep stale issues 2015-04-02 16:11:52 -07:00
Harshavardhana 138542ec65 Merge pull request #432 from harshavardhana/pr_out_build_everything_by_default 2015-04-02 14:38:45 -07:00
Harshavardhana 9c0b17c239 Build everything by default 2015-04-02 14:34:05 -07:00
Harshavardhana 3bfc29b3c1 Merge pull request #431 from harshavardhana/pr_out_update_cli_to_minio_io_cli 2015-04-02 12:50:33 -07:00
Harshavardhana 92136d49fd Update cli to minio-io/cli 2015-04-02 12:49:40 -07:00
Frederick F. Kautz IV 7a117bb6c5 Merge pull request #430 from fkautz/pr_out_updating_godep_to_minio_io_godep 2015-04-01 20:57:38 -07:00
Frederick F. Kautz IV a689769245 Updating godep to minio-io/godep 2015-04-01 20:57:27 -07:00
Frederick F. Kautz IV 1daee667b7 Merge pull request #429 from fkautz/pr_out_fixing_race_condition_in_api_test_go 2015-04-01 20:32:16 -07:00
Frederick F. Kautz IV 8757ccf9a3 Fixing race condition in api_test.go 2015-04-01 20:30:57 -07:00
Harshavardhana 315a03583e Merge pull request #428 from harshavardhana/pr_out_add_missing_mxj_package 2015-04-01 20:08:51 -07:00
Harshavardhana c5b927c9b5 Add missing mxj package 2015-04-01 20:08:39 -07:00
Harshavardhana f848c4095f Merge pull request #427 from harshavardhana/pr_out_parse_response_headers_in_tests 2015-04-01 20:08:09 -07:00
Harshavardhana 85e547d854 Parse response headers in tests 2015-04-01 20:07:51 -07:00
Harshavardhana f5226737e5 Merge pull request #426 from harshavardhana/pr_out_add_erasure_to_godep 2015-04-01 16:58:54 -07:00
Harshavardhana 92f408af5d Add erasure to godep 2015-04-01 16:56:43 -07:00
Frederick F. Kautz IV 07235399a1 Merge pull request #425 from fkautz/pr_out_minor_cleanup_of_memory_get_partial_object 2015-04-01 15:51:08 -07:00
Frederick F. Kautz IV 818b6d2e33 Minor cleanup of memory get partial object 2015-04-01 15:50:59 -07:00
Frederick F. Kautz IV e73c3b379f Merge pull request #424 from fkautz/pr_out_add_partial_object_support_to_donut_driver 2015-04-01 15:48:27 -07:00
Frederick F. Kautz IV 0c5ed6f3ba Add partial object support to donut driver 2015-04-01 15:48:12 -07:00
Frederick F. Kautz IV 27d4893a7e Merge pull request #423 from fkautz/pr_out_fix_whitespace 2015-04-01 12:31:11 -07:00
Frederick F. Kautz IV 563a914046 Fix whitespace 2015-04-01 12:30:58 -07:00
Frederick F. Kautz IV 994d7841c3 Merge pull request #422 from fkautz/pr_out_adding_comments_on_why_we_subtract_a_second_from_date1_in_an_api_test 2015-04-01 12:29:28 -07:00
Frederick F. Kautz IV 83f0f0971f Adding comments on why we subtract a second from date1 in an api test 2015-04-01 12:29:08 -07:00
Frederick F. Kautz IV 646ce59bc5 Merge pull request #421 from fkautz/pr_out_minor_modification_for_creating_temp_dir_in_api_test 2015-04-01 12:07:46 -07:00
Frederick F. Kautz IV 1f699a094b Minor modification for creating temp dir in api test 2015-04-01 12:07:33 -07:00
Frederick F. Kautz IV 224d53b3eb Merge pull request #420 from fkautz/pr_out_api_test_now_states_which_driver_is_currently_running 2015-04-01 12:06:35 -07:00
Frederick F. Kautz IV 5b1350b4bf api test now states which driver is currently running 2015-04-01 12:06:22 -07:00
Harshavardhana 44b4ef66e1 Merge pull request #419 from harshavardhana/pr_out_make_sure_in_api_we_handle_all_error_type_exclusively_and_return_certain_values_exclusively 2015-03-31 20:27:24 -07:00
Harshavardhana a56098b8c9 Make sure in API we handle all error type exclusively, and return certain values exclusively 2015-03-31 20:26:16 -07:00
Frederick F. Kautz IV 0491e1bbf1 Merge pull request #418 from fkautz/pr_out_moving_api_test_to_fixtures_for_drivers 2015-03-31 19:53:39 -07:00
Frederick F. Kautz IV 6136960cfd Moving api_test to fixtures for drivers 2015-03-31 19:53:25 -07:00
Frederick F. Kautz IV 252a8b54f5 Merge pull request #417 from fkautz/pr_out_adding_test_for_partial_objects 2015-03-31 19:07:52 -07:00
Frederick F. Kautz IV 959d90fcf7 Adding test for partial objects 2015-03-31 19:07:45 -07:00
Frederick F. Kautz IV 376dc30428 Merge pull request #416 from fkautz/pr_out_simplifying_error_handling_in_api_bucket_handlers 2015-03-31 19:07:38 -07:00
Frederick F. Kautz IV 62c4c997c2 Simplifying error handling in api bucket handlers 2015-03-30 14:27:32 -07:00
Frederick F. Kautz IV 06c329d26b Merge pull request #415 from fkautz/pr_out_api_bucket_handlers_errors_simplified 2015-03-30 11:40:40 -07:00
Frederick F. Kautz IV 318d9d5aa8 API Bucket Handlers errors simplified 2015-03-30 11:40:28 -07:00
Frederick F. Kautz IV 33414915a1 Merge pull request #414 from fkautz/pr_out_simplifying_error_response_writing_for_object_handlers 2015-03-29 22:03:24 -07:00
Frederick F. Kautz IV 7d657eb55c Simplifying error response writing for object handlers 2015-03-29 22:03:13 -07:00
Frederick F. Kautz IV c3cda5d9a8 Adding comments to errors 2015-03-29 22:03:13 -07:00
Frederick F. Kautz IV 53f116616f Merge pull request #413 from fkautz/pr_out_normalizing_imports_in_api 2015-03-29 21:41:47 -07:00
Frederick F. Kautz IV ded090a8b0 Normalizing imports in api 2015-03-29 21:41:38 -07:00
Frederick F. Kautz IV a99e60db84 Merge pull request #412 from fkautz/pr_out_more_api_cleanup 2015-03-29 21:38:44 -07:00
Frederick F. Kautz IV 8cbc1c2346 More api cleanup 2015-03-29 21:38:23 -07:00
Frederick F. Kautz IV 936520e6e0 Merge pull request #411 from fkautz/pr_out_cleaning_up_more_api_code 2015-03-29 21:07:00 -07:00
Frederick F. Kautz IV 452f0f8335 Cleaning up more api code 2015-03-29 21:06:51 -07:00
Frederick F. Kautz IV 0f6abe9ee3 Merge pull request #410 from fkautz/pr_out_rename_writeobjectheaders_to_setobjectheaders_fix_writing_multiple_headers_bug 2015-03-29 18:50:29 -07:00
Frederick F. Kautz IV d644233054 Rename writeObjectHeaders to setObjectHeaders, fix writing multiple headers bug 2015-03-29 18:49:32 -07:00
Harshavardhana 6fd78dba42 Merge pull request #409 from harshavardhana/pr_out_more_simplification_to_erasure_also_add_two_more_test_functions 2015-03-29 14:53:00 -07:00
Harshavardhana b748cf359a More simplification to erasure also add two more test functions 2015-03-29 14:52:13 -07:00
Harshavardhana 4c6677fd2c Merge pull request #408 from harshavardhana/pr_out_update_cli_with_new_changes 2015-03-29 13:44:43 -07:00
Harshavardhana 5defd8ffdd Update cli with new changes 2015-03-29 13:38:30 -07:00
Frederick F. Kautz IV 3c7d606571 Merge pull request #407 from fkautz/pr_out_minor_change_from_trace_to_error_log 2015-03-28 18:47:52 -07:00
Frederick F. Kautz IV 86b32c2147 Minor change from trace to error log 2015-03-28 18:47:36 -07:00
Frederick F. Kautz IV c728798137 Merge pull request #406 from fkautz/pr_out_simplfying_code_in_api_round_1_decoupling_functions_which_both_write_headers_and_data 2015-03-28 18:01:23 -07:00
Frederick F. Kautz IV d5db891094 Simplfying code in api, round 1. Decoupling functions which both write headers and data. 2015-03-28 18:01:00 -07:00
Frederick F. Kautz IV 83a4a95e9d Merge pull request #405 from fkautz/pr_out_refactoring_pkg_utils_log_copying_from_golang_s_log_and_modifying 2015-03-28 15:59:47 -07:00
Frederick F. Kautz IV b165efdfcb Refactoring pkg/utils/log, copying from golang's log and modifying 2015-03-28 15:58:48 -07:00
Frederick F. Kautz IV 7f753a3965 Merge pull request #404 from fkautz/pr_out_minor_style_fix 2015-03-28 13:24:27 -07:00
Frederick F. Kautz IV fd16de3675 Minor style fix 2015-03-28 13:23:54 -07:00
Harshavardhana f3f0a3a5f7 Merge pull request #403 from harshavardhana/pr_out_let_donut_driver_use_log_errorln_wrapper 2015-03-28 12:43:42 -07:00
Harshavardhana 767f4d1d8f Let donut driver use log.Errorln wrapper 2015-03-28 12:43:26 -07:00
Frederick F. Kautz IV fa6ee236f7 Merge pull request #402 from fkautz/pr_out_fix_for_readers_closing_in_erasure_early 2015-03-27 23:50:02 -07:00
Frederick F. Kautz IV c901d0fb32 Fix for readers closing in erasure early 2015-03-27 23:49:14 -07:00
Harshavardhana e8d0d4f4d8 Merge pull request #401 from harshavardhana/pr_out_add_missing_testify_mock 2015-03-27 23:27:33 -07:00
Harshavardhana fc3ee4d459 Add missing testify/mock 2015-03-27 23:27:17 -07:00
Frederick F. Kautz IV 8e8281e210 Merge pull request #400 from fkautz/pr_out_adding_tests_and_a_fix_for_get_object_where_bucket_is_not_found 2015-03-27 23:23:42 -07:00
Frederick F. Kautz IV 96e26335e2 Adding tests and a fix for get object where bucket is not found 2015-03-27 23:23:22 -07:00
Frederick F. Kautz IV 166c620263 Merge pull request #399 from fkautz/pr_out_fixing_donut_location 2015-03-27 12:44:29 -07:00
Frederick F. Kautz IV ad370f341b Fixing donut location 2015-03-27 12:44:13 -07:00
Frederick F. Kautz IV c486d5c3f7 Merge pull request #398 from fkautz/pr_out_iodine_now_serializes_error_type_as_string 2015-03-26 22:48:26 -07:00
Frederick F. Kautz IV 17d432e7f1 Iodine now serializes error type as string 2015-03-26 22:48:09 -07:00
Frederick F. Kautz IV 9883af2337 Merge pull request #397 from fkautz/pr_out_updating_iodine_to_match_new_api 2015-03-26 15:55:19 -07:00
Frederick F. Kautz IV 53439d7768 Updating iodine to match new api 2015-03-26 15:55:06 -07:00
Frederick F. Kautz IV ebc1e062a9 Merge pull request #396 from fkautz/pr_out_removing_todo 2015-03-26 11:33:55 -07:00
Frederick F. Kautz IV c5f10df957 Removing TODO 2015-03-26 11:33:50 -07:00
Frederick F. Kautz IV f4790fc440 Merge pull request #395 from fkautz/pr_out_refactoring_erasure_each_block_is_encoded_by_a_function_iodine_included 2015-03-26 11:32:55 -07:00
Frederick F. Kautz IV eaeeb4bef0 Refactoring erasure, each block is encoded by a function. Iodine included. 2015-03-26 11:32:39 -07:00
Frederick F. Kautz IV 31746fdeb2 Adding iodine to donutObjectWriter.Write 2015-03-26 10:49:03 -07:00
Frederick F. Kautz IV bfbb97c98f Merge pull request #393 from fkautz/pr_out_adding_iodine_to_object_writer 2015-03-26 10:42:57 -07:00
Frederick F. Kautz IV f7a300400e Merge pull request #392 from fkautz/pr_out_adding_iodine_to_node_local 2015-03-26 10:42:50 -07:00
Frederick F. Kautz IV 3c37218d7d Merge pull request #391 from fkautz/pr_out_addnode_fails_with_proper_error_code_when_bucketid_is_malformed 2015-03-26 10:42:42 -07:00
Frederick F. Kautz IV caf7e41499 Adding iodine to object_writer 2015-03-26 10:41:40 -07:00
Frederick F. Kautz IV 5cdf2564a5 Adding iodine to node_local 2015-03-26 10:21:24 -07:00
Frederick F. Kautz IV 70a2217eb2 AddNode fails with proper error code when bucketid is malformed 2015-03-26 10:02:40 -07:00
Frederick F. Kautz IV 8cf66ede66 Merge pull request #390 from fkautz/pr_out_adding_iodine_to_donut 2015-03-26 09:57:49 -07:00
Frederick F. Kautz IV cc64417481 Adding iodine to donut 2015-03-26 09:57:21 -07:00
Harshavardhana 58bf15e899 Merge pull request #389 from harshavardhana/pr_out_update_makefile 2015-03-25 23:10:18 -07:00
Harshavardhana 4d57ca7c44 Update makefile 2015-03-25 23:10:03 -07:00
Anand Babu (AB) Periasamy 4cf85ccc71 Merge pull request #388 from abperiasamy/clean-build-constants
make clean build-constants.go
2015-03-25 23:05:21 -07:00
Anand Babu (AB) Periasamy e14ba846b5 make clean build-constants.go 2015-03-25 23:04:27 -07:00
Anand Babu (AB) Periasamy 7d0fb1b9c6 Merge pull request #387 from abperiasamy/git-commit-id-generator
git commit hash generator
2015-03-25 22:58:54 -07:00
Anand Babu (AB) Periasamy 3c4aa85c69 git commit hash generator 2015-03-25 22:57:30 -07:00
Harshavardhana aa44548a67 Merge pull request #386 from fkautz/pr_out_updating_iodine_to_support_new_iodine_error_error_map_string_string_error_method 2015-03-25 21:17:29 -07:00
Frederick F. Kautz IV 40e311a919 Updating iodine to support new iodine.Error(error, map[string]string) error method 2015-03-25 19:12:55 -07:00
Harshavardhana 68f36f5e08 Merge pull request #385 from abperiasamy/erasure_cache_tbls_matrix 2015-03-25 19:11:07 -07:00
Anand Babu (AB) Periasamy b44d2100db cache decode matrix tables and matrix 2015-03-25 19:09:34 -07:00
Harshavardhana 7503b7f9d1 Merge pull request #384 from harshavardhana/pr_out_fix_golint_complaints 2015-03-25 19:01:52 -07:00
Harshavardhana 2d0be3e3b2 fix golint complaints 2015-03-25 19:01:36 -07:00
Harshavardhana 638ed36cc6 Merge pull request #382 from abperiasamy/janitor-erasure-decode 2015-03-25 18:13:46 -07:00
Anand Babu (AB) Periasamy bd39768de2 janitor duty on erasure-decode 2015-03-25 18:02:03 -07:00
Frederick F. Kautz IV db2ac35da5 Merge pull request #381 from fkautz/pr_out_upgrading_iodine 2015-03-25 17:32:36 -07:00
Frederick F. Kautz IV 9b9d5e9d39 Upgrading iodine 2015-03-25 17:32:25 -07:00
Frederick F. Kautz IV 28355c7aa6 Merge pull request #380 from fkautz/pr_out_adding_iodine_to_donut_bucket 2015-03-25 17:05:36 -07:00
Frederick F. Kautz IV eff48971ad Adding iodine to donut bucket 2015-03-25 17:05:26 -07:00
Frederick F. Kautz IV d81472f836 Merge pull request #379 from fkautz/pr_out_adding_iodine_to_pkg_server_server_go 2015-03-25 17:04:41 -07:00
Frederick F. Kautz IV d52dd5ed5b Adding iodine to pkg/server/server.go 2015-03-25 17:04:26 -07:00
Frederick F. Kautz IV 673072579d Merge pull request #378 from fkautz/pr_out_adding_iodine_to_main_go 2015-03-25 17:03:45 -07:00
Frederick F. Kautz IV d54999c4d0 Adding iodine to main.go 2015-03-25 17:03:34 -07:00
Harshavardhana 765d7da890 Merge pull request #377 from harshavardhana/pr_out_add_gocyclo_into_source_build_choosing_cyclomatic_complexity_tolerance_of_15_and_below 2015-03-25 15:59:19 -07:00
Harshavardhana 58082cd8dc Add gocyclo into source build, choosing cyclomatic complexity tolerance of 15 and below 2015-03-25 15:57:17 -07:00
Harshavardhana c366fdd2d8 loop only on readers once 2015-03-25 14:48:46 -07:00
Harshavardhana d9bd5e2e10 Merge pull request #376 from harshavardhana/pr_out_comment_exported_functions_getencodedblockslen_getencodedblocklen 2015-03-25 13:32:59 -07:00
Harshavardhana e1f4ed4650 Comment exported functions GetEncodedBlocksLen, GetEncodedBlockLen 2015-03-25 13:32:35 -07:00
Harshavardhana fab6892bc3 Merge pull request #375 from harshavardhana/pr_out_golint_fixes 2015-03-25 13:25:38 -07:00
Harshavardhana 2cbd15b690 Golint fixes 2015-03-25 13:25:25 -07:00
Harshavardhana 9503a4df33 Merge pull request #374 from harshavardhana/pr_out_remove_unnecessary_if_block 2015-03-25 12:58:29 -07:00
Harshavardhana d967babbaa Remove unnecessary if <block> 2015-03-25 12:58:15 -07:00
Frederick F. Kautz IV 5461ab2605 Merge pull request #373 from fkautz/pr_out_fix_build_break 2015-03-25 11:50:13 -07:00
Frederick F. Kautz IV 5c0d92eb39 Fix build break 2015-03-25 11:50:05 -07:00
Harshavardhana 2f611e61ea Merge pull request #372 from harshavardhana/pr_out_build_fix_remove_errors_not_used 2015-03-25 11:49:19 -07:00
Harshavardhana 54519bc0b9 Build fix, remove 'errors' not used 2015-03-25 11:49:04 -07:00
Frederick F. Kautz IV 63194c321d Merge pull request #371 from fkautz/pr_out_adding_global_state_to_iodine 2015-03-25 11:45:52 -07:00
Frederick F. Kautz IV 337df7f7ec Adding global state to iodine 2015-03-25 11:45:14 -07:00
Harshavardhana 0662f9e019 Merge pull request #207 from vadmeste/add_docker_file
Add Dockerfile to build a docker image with embarked minio server
2015-03-25 11:35:32 -07:00
Harshavardhana d8361f8bb4 Merge pull request #370 from harshavardhana/pr_out_use_commitid_as_version 2015-03-25 11:20:47 -07:00
Harshavardhana 47cd2c94c8 Use commitID as version 2015-03-25 11:20:34 -07:00
Frederick F. Kautz IV da89132def Merge pull request #369 from fkautz/pr_out_updating_iodine_now_has_global_state 2015-03-25 10:40:08 -07:00
Frederick F. Kautz IV abe49919ed Updating iodine, now has global state. 2015-03-25 10:39:44 -07:00
Anand Babu (AB) Periasamy 31482659be Merge pull request #368 from abperiasamy/commit-id
commid_id support
2015-03-25 01:51:13 -07:00
Anand Babu (AB) Periasamy 62af4c0b52 commid_id support 2015-03-25 01:50:01 -07:00
Frederick F. Kautz IV d6507305ac Merge pull request #367 from fkautz/pr_out_updating_iodine 2015-03-25 00:46:10 -07:00
Frederick F. Kautz IV be229473b5 Updating iodine 2015-03-25 00:43:48 -07:00
Harshavardhana d909a0e297 Merge pull request #366 from harshavardhana/pr_out_fix_nil_pointer_dereference_when_err_is_nil 2015-03-25 00:37:38 -07:00
Harshavardhana 0f8021abd1 Fix nil pointer dereference when err is nil 2015-03-25 00:37:25 -07:00
Frederick F. Kautz IV e8d35258f1 Merge pull request #365 from fkautz/pr_out_adding_iodine_annotation_to_donut_start_path 2015-03-25 00:27:58 -07:00
Frederick F. Kautz IV 1be3766ae6 Adding iodine annotation to donut.Start(path) 2015-03-25 00:27:45 -07:00
Frederick F. Kautz IV 12a17f1ed7 Merge pull request #364 from fkautz/pr_out_using_iodine_in_donut_start_ 2015-03-25 00:25:41 -07:00
Frederick F. Kautz IV d06f5afdfc Using iodine in donut.Start() 2015-03-25 00:25:27 -07:00
Harshavardhana 4d165dbcbb Merge pull request #363 from harshavardhana/pr_out_avoid_empty_if_else_body_ 2015-03-25 00:24:59 -07:00
Harshavardhana b3c3a8d6f2 Avoid empty if else body.. 2015-03-25 00:24:41 -07:00
Frederick F. Kautz IV 029e49a7d2 Merge pull request #362 from fkautz/pr_out_updating_check_v1 2015-03-25 00:21:55 -07:00
Frederick F. Kautz IV 2e857a6f94 Updating check.v1 2015-03-25 00:21:43 -07:00
Frederick F. Kautz IV 2aa1da16d7 Merge pull request #361 from fkautz/pr_out_updating_iodine 2015-03-25 00:18:00 -07:00
Frederick F. Kautz IV 2acd66ae96 Updating iodine 2015-03-25 00:17:50 -07:00
Harshavardhana bbaa72f67d Merge pull request #360 from harshavardhana/pr_out_fix_minio_hang_in_donut_driver 2015-03-25 00:16:22 -07:00
Harshavardhana ada98c56c0 Fix minio hang in donut driver.
remove sending err to errorChannel until we figure out the right fix.
2015-03-25 00:15:36 -07:00
Frederick F. Kautz IV 938a0fa4a9 Merge pull request #359 from fkautz/pr_out_adding_iodine 2015-03-25 00:04:56 -07:00
Frederick F. Kautz IV 1ae74591f6 Adding iodine 2015-03-24 23:54:49 -07:00
Frederick F. Kautz IV 3fc54eea3a Merge pull request #357 from fkautz/pr_out_populate_buckets_at_start 2015-03-24 21:04:48 -07:00
Frederick F. Kautz IV dd5ba865ff Merge remote-tracking branch 'origin/master' into HEAD
Conflicts:
	pkg/drivers/donut/donut.go
	pkg/storage/donut/bucket.go
	pkg/storage/donut/donut.go
	pkg/storage/donut/donut_test.go
	pkg/storage/donut/donutdriver.go
2015-03-24 21:04:08 -07:00
Harshavardhana a311a9c4b8 Merge pull request #358 from harshavardhana/pr_out_move_from_codegangsta_cli_to_minio_io_cli_fork 2015-03-24 20:41:04 -07:00
Harshavardhana d0d585efc1 Move from codegangsta/cli to minio-io/cli fork 2015-03-24 20:40:19 -07:00
Frederick F. Kautz IV cf2550b267 Populate buckets at start 2015-03-24 19:58:03 -07:00
Harshavardhana 4c7a61a68d Merge pull request #356 from harshavardhana/pr_out_erasure_technique_is_now_uint8_handle_it_appropriately 2015-03-24 19:13:09 -07:00
Harshavardhana 653ea50a59 Erasure technique is now uint8, handle it appropriately 2015-03-24 19:12:52 -07:00
Harshavardhana 7d25490a2e Merge pull request #355 from abperiasamy/janitor_erasure 2015-03-24 19:09:20 -07:00
Anand Babu (AB) Periasamy fa9b1f341b erasure encode janitor duty 2015-03-24 18:47:53 -07:00
Harshavardhana 62b69048ec Merge pull request #354 from harshavardhana/pr_out_handle_errors_properly_during_erasure_decoding_also_populate_technique_and_verify 2015-03-24 18:14:40 -07:00
Harshavardhana 6a87ed001c Handle errors properly during erasure Decoding, also populate technique and verify 2015-03-24 18:14:13 -07:00
Harshavardhana d58dbe3fce Merge pull request #353 from harshavardhana/pr_out_code_restructuring_assigning_proper_subsystems_to_each 2015-03-24 06:48:28 -07:00
Harshavardhana 0474439b43 Code restructuring, assigning proper subsystems to each
- Drivers contain
    * donut/*
    * file/*
    * memory/*

 - Storage format contains
    * donut/*
      - GetObject() --> renamed to GetObjectReader()
      - Deleted stale objectwriter.go, renamed donutwriter.go to object_writer.go

Simplifying, and documenting codebase further
2015-03-24 06:47:10 -07:00
Frederick F. Kautz IV 6dd7a9d654 Merge pull request #352 from fkautz/pr_out_adding_donut_backend_and_setting_as_default 2015-03-23 20:07:52 -07:00
Frederick F. Kautz IV 3c4012f1e7 Adding donut backend and setting as default 2015-03-23 20:07:22 -07:00
Harshavardhana 7c1c4b8a02 Merge pull request #351 from harshavardhana/pr_out_implement_log_package_as_drop_in_replacement_for_handling_debug_log_level 2015-03-23 18:55:14 -07:00
Harshavardhana 914962bd93 Implement log package as drop-in replacement for handling Debug log-level 2015-03-23 18:18:11 -07:00
Frederick F. Kautz IV 2191fb739f Merge pull request #350 from fkautz/pr_out_running_gofmt_manually_auto_gofmt_didn_t_simplify_code 2015-03-23 12:26:52 -07:00
Frederick F. Kautz IV f91f5e59ee Running gofmt manually, auto gofmt didn't simplify code 2015-03-23 12:26:41 -07:00
Frederick F. Kautz IV 56a298fd6a Refactoring method variable names for erasureWriter struct 2015-03-23 12:25:20 -07:00
Frederick F. Kautz IV 742a186d10 Merge pull request #348 from fkautz/pr_out_adding_sys_as_reserved_in_erasurewriter 2015-03-23 11:56:37 -07:00
Frederick F. Kautz IV d57e9d6c18 Adding sys. as reserved in erasureWriter 2015-03-23 11:56:24 -07:00
Frederick F. Kautz IV 920c734b2f Merge pull request #347 from fkautz/pr_out_switching_content_hashing_from_sha512_to_md5 2015-03-23 11:46:28 -07:00
Frederick F. Kautz IV b2f47ef446 Switching content hashing from sha512 to md5 2015-03-23 11:46:19 -07:00
Harshavardhana 80892c5c9b Merge pull request #346 from harshavardhana/pr_out_rename_parms_as_params_for_brevity_and_misc_cleanup 2015-03-22 20:27:11 -07:00
Harshavardhana b8e9834faa Rename parms as --> params for brevity and misc cleanup 2015-03-22 20:26:01 -07:00
Frederick F. Kautz IV 9d5a6329ba Merge pull request #345 from fkautz/pr_out_adding_sha512_support_for_pre_encoded_data_and_verification_on_decode 2015-03-22 20:11:52 -07:00
Frederick F. Kautz IV b2c3172095 Adding sha512 support for pre-encoded data and verification on decode 2015-03-22 20:11:25 -07:00
Frederick F. Kautz IV f471915646 Merge pull request #344 from fkautz/pr_out_exorcising_donutbox 2015-03-22 19:55:50 -07:00
Frederick F. Kautz IV befac7d047 Exorcising donutbox 2015-03-22 19:55:15 -07:00
Frederick F. Kautz IV 331a3e80a3 Merge pull request #343 from fkautz/pr_out_reading_correct_block_size_in_erasure_coded_data 2015-03-22 18:49:41 -07:00
Frederick F. Kautz IV eb8005cc65 Reading correct block size in erasure coded data 2015-03-22 18:49:30 -07:00
Frederick F. Kautz IV 601f5c77fe Merge pull request #342 from abperiasamy/janitor_remove_k_m 2015-03-22 18:48:51 -07:00
Anand Babu (AB) Periasamy b9b0b35edf removed private k and m and some more cleanups 2015-03-22 18:22:09 -07:00
Frederick F. Kautz IV 293e438830 Merge pull request #341 from abperiasamy/janitor 2015-03-22 17:34:25 -07:00
Anand Babu (AB) Periasamy 3a76229551 encoded size function is now public + some janitor duty 2015-03-22 17:17:53 -07:00
Harshavardhana 562a57be84 Merge pull request #340 from harshavardhana/pr_out_make_sure_we_use_o_excl_with_o_create_to_make_sure_we_don_t_trip_over_existing_file 2015-03-22 15:56:31 -07:00
Harshavardhana 3929135c34 Make sure we use O_EXCL with O_CREATE to make sure we don't trip over existing file 2015-03-22 15:55:40 -07:00
Harshavardhana b2ee7d989d Merge pull request #339 from harshavardhana/pr_out_de_couple_donut_into_smaller_files_useful_for_ease_in_external_integration 2015-03-22 15:53:26 -07:00
Harshavardhana 2fa9320df2 De-couple donut into smaller files, useful for ease in external integration 2015-03-22 15:43:37 -07:00
Frederick F. Kautz IV 38bfc7a949 Merge pull request #338 from fkautz/pr_out_removing_log_tracers 2015-03-22 15:39:58 -07:00
Frederick F. Kautz IV 55f3659bb3 Removing log tracers 2015-03-22 15:39:50 -07:00
Frederick F. Kautz IV 4433142813 Merge pull request #337 from fkautz/pr_out_adding_list_objects_to_donut 2015-03-22 15:34:12 -07:00
Frederick F. Kautz IV 03f51eac29 Adding list objects to donut 2015-03-22 15:33:52 -07:00
Anis Elleuch 64fed14aac Add Dockerfile to build a docker image with embarked minio server 2015-03-22 14:52:27 -07:00
Harshavardhana dcd9a8ae12 Merge pull request #336 from harshavardhana/pr_out_donutfilewriter_should_return_value_of_file_close_ 2015-03-22 14:51:47 -07:00
Harshavardhana 4b9fbd3b3a DonutfileWriter should return value of file.Close() 2015-03-22 14:51:18 -07:00
Frederick F. Kautz IV ab89298250 Merge pull request #335 from fkautz/pr_out_minor_change_removing_unnecessary_commented_method 2015-03-22 12:44:54 -07:00
Frederick F. Kautz IV ced6edc9fe Minor change, removing unnecessary commented method 2015-03-22 12:44:45 -07:00
Frederick F. Kautz IV 9fde4daa29 Merge pull request #334 from fkautz/pr_out_adding_getobjectmetadata_to_donut 2015-03-22 12:36:59 -07:00
Frederick F. Kautz IV 99cf484488 Adding GetObjectMetadata to donut 2015-03-22 12:36:51 -07:00
Frederick F. Kautz IV 7d6534088e Merge pull request #333 from fkautz/pr_out_removing_gob_from_donut_driver 2015-03-22 12:17:36 -07:00
Frederick F. Kautz IV 703af6c3ce Removing gob from donut driver 2015-03-22 12:17:12 -07:00
Harshavardhana 537870ec4f Merge pull request #332 from harshavardhana/pr_out_fix_build_issues_for_new_donutdriver_ 2015-03-22 02:53:39 -07:00
Harshavardhana 95affcb119 Fix build issues for new DonutDriver() 2015-03-22 02:53:21 -07:00
Frederick F. Kautz IV 15b205c439 Merge pull request #331 from fkautz/pr_out_new_donut_driver_with_local_file_encoding 2015-03-22 00:40:30 -07:00
Frederick F. Kautz IV 933d44c656 New donut driver with local file encoding 2015-03-22 00:40:21 -07:00
Harshavardhana d92a179cbc Merge pull request #330 from harshavardhana/pr_out_return_error_during_joinfiles_back_to_the_caller_for_inspection 2015-03-20 03:17:18 -07:00
Harshavardhana a8056c4c12 Return error during JoinFiles back to the caller for inspection 2015-03-20 03:17:08 -07:00
Harshavardhana 8859232f93 Merge pull request #329 from harshavardhana/pr_out_update_license_header_mini_should_be_minimalist_really 2015-03-19 14:36:08 -07:00
Harshavardhana 2b0b5f014a Update license header Mini should be Minimalist really 2015-03-19 14:35:50 -07:00
Harshavardhana 321c6dbe09 Merge pull request #328 from harshavardhana/pr_out_fix_bucketpolicy_to_handle_s3_and_minio_policy_names_separately 2015-03-19 12:23:02 -07:00
Harshavardhana c3602967ab Fix bucketpolicy to handle s3 and minio policy names separately.
Also fix an apparent bug in GetBucketPolicy{}
2015-03-19 12:22:14 -07:00
Harshavardhana 7496d89f8f Merge pull request #327 from harshavardhana/pr_out_resource_list_updates 2015-03-19 00:49:17 -07:00
Harshavardhana 6eb5315249 Resource list updates 2015-03-19 00:47:34 -07:00
Harshavardhana 8293c787bf Merge pull request #326 from harshavardhana/pr_out_refactor_to_move_config_handling_into_api 2015-03-18 22:49:19 -07:00
Harshavardhana a1baed3bbc Refactor to move config handling into api/ 2015-03-18 22:49:02 -07:00
Harshavardhana b61daa0f87 Merge pull request #325 from harshavardhana/pr_out_restructure_minio_api_move_signature_checks_from_utils_to_api 2015-03-18 18:17:31 -07:00
Harshavardhana 7ce3ab3193 Restructure minio api, move signature checks from utils to Api. 2015-03-18 18:16:19 -07:00
Frederick F. Kautz IV 7ddf6a9f8f Merge pull request #324 from fkautz/pr_out_adding_interfaces_for_donut_driver 2015-03-18 14:27:20 -07:00
Frederick F. Kautz IV 2c69433588 Adding interfaces for donut driver 2015-03-18 14:27:10 -07:00
Frederick F. Kautz IV 4ab19943e8 Merge pull request #323 from fkautz/pr_out_renaming_files_to_match 2015-03-18 12:26:53 -07:00
Frederick F. Kautz IV bf86e78714 Renaming files to match 2015-03-18 12:26:44 -07:00
Frederick F. Kautz IV e625bf2bb5 Merge pull request #322 from fkautz/pr_out_renaming_encoded_driver_to_donutstorage 2015-03-18 12:25:53 -07:00
Frederick F. Kautz IV 1c9e550ee6 Renaming encoded driver to donutstorage 2015-03-18 12:25:37 -07:00
Frederick F. Kautz IV 0fdd9f6fc0 Merge pull request #321 from fkautz/pr_out_adding_interfaces_for_implementing_against 2015-03-17 22:34:18 -07:00
Frederick F. Kautz IV d7f00194b5 Adding interfaces for implementing against 2015-03-17 22:33:59 -07:00
Frederick F. Kautz IV 982a52e0d4 Merge pull request #320 from fkautz/pr_out_removing_block_size_from_donut_writer_no_longer_necessary 2015-03-17 14:25:08 -07:00
Frederick F. Kautz IV d6be8d3517 Removing block size from donut writer, no longer necessary 2015-03-17 14:24:59 -07:00
Harshavardhana c551757415 Merge pull request #319 from harshavardhana/pr_out_now_minioapi_handles_content_md5_set_during_putobject_ 2015-03-17 13:33:31 -07:00
Harshavardhana 74b3d092f2 Now MinioAPI handles Content-MD5 set during putObject()
- This change also facilitates proper error response
    in case of md5 mismatch or corruption
  - TODO a test function needs to be implemented
2015-03-17 13:32:13 -07:00
Harshavardhana 42006c2ab0 Merge pull request #318 from harshavardhana/pr_out_remove_contenttype_pseudo_func_ 2015-03-17 00:47:46 -07:00
Frederick F. Kautz IV 1dcb8eceb7 Merge pull request #317 from fkautz/pr_out_fixing_order_of_input_and_layout_in_time_parse 2015-03-17 00:47:34 -07:00
Harshavardhana dccf32e5c4 Remove contenttype pseudo func() 2015-03-17 00:47:22 -07:00
Frederick F. Kautz IV 90b337a3e8 Fixing order of input and layout in time.Parse 2015-03-17 00:47:17 -07:00
Frederick F. Kautz IV 4770f611e0 Merge pull request #316 from fkautz/pr_out_moving_to_more_accurate_rfc3339 2015-03-17 00:46:01 -07:00
Frederick F. Kautz IV 25725c442a Moving to more accurate RFC3339 2015-03-17 00:45:50 -07:00
Frederick F. Kautz IV 639f542ac9 Merge pull request #315 from fkautz/pr_out_moving_from_iso8601_to_rfc3339 2015-03-17 00:42:25 -07:00
Frederick F. Kautz IV e36fa95f1f Moving from iso8601 to RFC3339 2015-03-17 00:42:08 -07:00
Frederick F. Kautz IV 6070d18217 Merge pull request #314 from fkautz/pr_out_encoded_now_passes_tests_enabling 2015-03-17 00:34:18 -07:00
Frederick F. Kautz IV 598eb5192e Encoded now passes tests, enabling. 2015-03-17 00:33:49 -07:00
Harshavardhana e5e6e4cfa7 Merge pull request #313 from harshavardhana/pr_out_encoded_storage_type_now_feature_complete 2015-03-16 23:46:26 -07:00
Harshavardhana 6d71935ea5 Encoded storage type now feature complete 2015-03-16 23:42:45 -07:00
Frederick F. Kautz IV 1766b588fb Merge pull request #312 from fkautz/pr_out_list_objects_in_buckets 2015-03-16 20:43:50 -07:00
Frederick F. Kautz IV 34cf6682fe list objects in buckets 2015-03-16 20:43:05 -07:00
Frederick F. Kautz IV d99435963b Merge pull request #311 from fkautz/pr_out_switching_from_base64_to_hex_for_etag 2015-03-16 18:39:07 -07:00
Frederick F. Kautz IV 1a88b36c55 Switching from base64 to hex for etag 2015-03-16 18:38:42 -07:00
Harshavardhana 81f1d3c195 Merge pull request #310 from harshavardhana/pr_out_make_blocksize_as_constant 2015-03-16 18:20:22 -07:00
Harshavardhana b495f15178 Make blockSize as constant 2015-03-16 18:20:01 -07:00
Frederick F. Kautz IV cda13750f7 Merge pull request #309 from fkautz/pr_out_performing_etag_off_of_bytes_rather_than_md5_string 2015-03-16 18:15:44 -07:00
Frederick F. Kautz IV 211b084e50 Performing etag off of bytes rather than md5 string 2015-03-16 18:15:37 -07:00
Frederick F. Kautz IV a8c8e4d335 Merge pull request #308 from fkautz/pr_out_metadata_now_stores_hex_md5_not_base64_minio_api_now_converts_md5_hex_to_base64 2015-03-16 18:03:46 -07:00
Frederick F. Kautz IV 583c32c774 Metadata now stores hex md5, not base64. Minio API now converts md5 hex to base64. 2015-03-16 18:03:22 -07:00
Frederick F. Kautz IV ed5051a795 Merge pull request #307 from fkautz/pr_out_better_handling_of_metadata_in_encoded 2015-03-16 17:41:28 -07:00
Frederick F. Kautz IV 10ae089c46 Better handling of metadata in encoded 2015-03-16 17:40:59 -07:00
Harshavardhana dc1589bb5f Merge pull request #306 from harshavardhana/pr_out_some_necessary_cleanup 2015-03-16 12:06:23 -07:00
Harshavardhana 15f68972a5 Some necessary cleanup
- Rename 'fs' as 'file' for brevity
  - Rename 'inmemory' as 'memory' for brevity
  - Change everywhere else
2015-03-16 11:46:16 -07:00
Harshavardhana 772d3bc3d4 Merge pull request #305 from harshavardhana/pr_out_remove_x509_package_janitor_continuation_monad 2015-03-15 19:45:09 -07:00
Harshavardhana 765fde13f1 Remove x509 package, janitor continuation monad 2015-03-15 19:44:55 -07:00
Harshavardhana bf04d125fd Merge pull request #304 from harshavardhana/pr_out_move_from_fmt_errorf_to_errors_new 2015-03-15 19:42:23 -07:00
Harshavardhana 596eeb097e Move from fmt.Errorf to errors.New
In many cases fmt.Errorf is good enough, but since
error is an interface, you can use arbitrary data
structures as error values, to allow callers to
inspect the details of the error.
2015-03-15 19:41:16 -07:00
Frederick F. Kautz IV 7936b05451 Merge pull request #303 from fkautz/pr_out_decoding_and_returning_objects_now_works 2015-03-15 19:02:12 -07:00
Frederick F. Kautz IV a589ddaddf Decoding and returning objects now works 2015-03-15 19:02:00 -07:00
Frederick F. Kautz IV a737246f92 Merge pull request #302 from fkautz/pr_out_metadata_and_writing_the_object_are_now_both_committed_together 2015-03-15 17:43:21 -07:00
Frederick F. Kautz IV 682bf085c4 Metadata and writing the object are now both committed together. 2015-03-15 17:42:33 -07:00
Frederick F. Kautz IV 3a2419d20f Merge pull request #300 from fkautz/pr_out_adding_create_bucket_to_encoded 2015-03-15 12:28:39 -07:00
Frederick F. Kautz IV 96d0a089b8 Adding create bucket to encoded 2015-03-15 12:28:24 -07:00
Harshavardhana 4744149ec4 Merge pull request #299 from harshavardhana/pr_out_skip_uinimplemented_tests_and_some_cleanup 2015-03-15 01:24:23 -07:00
Harshavardhana 3f95c55067 Skip uinimplemented tests and some cleanup 2015-03-15 01:23:57 -07:00
Frederick F. Kautz IV 6990a64d01 Merge pull request #298 from fkautz/pr_out_working_in_memory_donut_driver 2015-03-15 00:41:14 -07:00
Frederick F. Kautz IV 3e453a394a Working in memory donut driver 2015-03-15 00:41:06 -07:00
Frederick F. Kautz IV e601d997f3 Merge pull request #297 from fkautz/pr_out_more_testing 2015-03-14 19:30:02 -07:00
Frederick F. Kautz IV 15d5e74837 More testing 2015-03-14 19:29:54 -07:00
Frederick F. Kautz IV d52ca9a238 Merge pull request #296 from fkautz/pr_out_inmemory_donutbox_is_now_thread_safe 2015-03-14 19:21:44 -07:00
Frederick F. Kautz IV 7e61696901 Inmemory donutbox is now thread safe 2015-03-14 19:21:34 -07:00
Frederick F. Kautz IV 74eb6067f6 Merge pull request #295 from fkautz/pr_out_adding_start_of_inmem_donut 2015-03-14 18:02:43 -07:00
Frederick F. Kautz IV 85da9fc627 Adding start of inmem donut 2015-03-14 18:02:27 -07:00
Frederick F. Kautz IV b441a27c67 Merge pull request #294 from fkautz/pr_out_renaming_singledisk_to_encoded 2015-03-14 11:39:03 -07:00
Frederick F. Kautz IV 54472c18fe Renaming singledisk to encoded 2015-03-14 11:37:43 -07:00
Frederick F. Kautz IV 348c4d9a88 Removing old donut format 2015-03-14 11:36:19 -07:00
Frederick F. Kautz IV 2f4b92eb8d Minor refactor to prepare for file version of donut 2015-03-14 11:34:45 -07:00
Harshavardhana dffee21cde Merge pull request #292 from harshavardhana/pr_out_update_erasure_readme_with_supported_architecture_list 2015-03-12 16:37:40 -07:00
Harshavardhana f7b62caccc Update erasure README with supported architecture list 2015-03-12 16:37:08 -07:00
Harshavardhana 959d482614 Merge pull request #291 from harshavardhana/pr_out_cosmetic_changes 2015-03-12 02:15:51 -07:00
Harshavardhana f7fd526b28 Cosmetic changes 2015-03-12 02:11:04 -07:00
Harshavardhana 1e4a47ac5f Merge pull request #290 from harshavardhana/pr_out_add_crc32c_license_headers_golang_and_minio 2015-03-12 02:09:06 -07:00
Harshavardhana 4c86e594d6 Add crc32c license headers Golang and Minio 2015-03-12 02:05:05 -07:00
Harshavardhana a049024643 Merge pull request #289 from harshavardhana/pr_out_remove_minio_calc_chunk_size_c_code_to_write_one_in_golang 2015-03-12 02:04:08 -07:00
Harshavardhana e27ba44d94 Remove minio_calc_chunk_size() C code to write one in Golang 2015-03-12 02:03:04 -07:00
Frederick F. Kautz IV 1047383bcf Merge pull request #288 from fkautz/pr_out_more_refactoring_to_meet_new_donut_spec 2015-03-12 01:52:35 -07:00
Frederick F. Kautz IV 94fe03cfc1 More refactoring to meet new donut spec 2015-03-12 01:52:14 -07:00
Harshavardhana 9889796c9c Merge pull request #287 from harshavardhana/pr_out_restructure_and_use_human_readable_names 2015-03-12 00:38:19 -07:00
Harshavardhana 67888cbaa9 Restructure and use human readable names 2015-03-12 00:36:33 -07:00
Harshavardhana e21020b337 Merge pull request #280 from harshavardhana/pr_out_http_range_support_wip
Get object range request added
2015-03-12 00:11:38 -07:00
Harshavardhana a42a48a455 Get object range request added 2015-03-12 00:07:27 -07:00
Frederick F. Kautz IV 1cfa2062ea Merge pull request #285 from fkautz/pr_out_rename_storebucket_to_createbucket 2015-03-11 20:14:49 -07:00
Frederick F. Kautz IV 24d5018037 Rename StoreBucket to CreateBucket 2015-03-11 20:14:40 -07:00
Frederick F. Kautz IV e0ef70e11b Merge pull request #284 from fkautz/pr_out_adding_copyright 2015-03-11 19:59:32 -07:00
Frederick F. Kautz IV 8c6aa45458 Adding copyright 2015-03-11 19:59:20 -07:00
Frederick F. Kautz IV a749f659aa Merge pull request #283 from fkautz/pr_out_adding_object_donut_type 2015-03-11 19:57:03 -07:00
Frederick F. Kautz IV 7971b66e60 Adding object donut type 2015-03-11 19:56:18 -07:00
Frederick F. Kautz IV 3af2894a9e Merge pull request #282 from fkautz/pr_out_adding_stubes_for_new_single_disk_driver 2015-03-11 13:36:35 -07:00
Frederick F. Kautz IV ec9b20a94f Adding stubes for new single disk driver 2015-03-11 13:36:21 -07:00
Frederick F. Kautz IV a831757064 Merge pull request #281 from fkautz/pr_out_adding_idea_files_to_gitignore 2015-03-11 12:05:27 -07:00
Frederick F. Kautz IV 9da26de696 Adding IDEA files to gitignore 2015-03-11 12:05:12 -07:00
Harshavardhana cd6a68400d Merge pull request #279 from harshavardhana/pr_out_rename_dateformat_with_understandable_name_iso8601format_ 2015-03-10 01:52:23 -07:00
Harshavardhana a24bfb007d Rename dateFormat with understandable name `iso8601Format` 2015-03-10 01:51:34 -07:00
Harshavardhana dd0469542b Merge pull request #278 from harshavardhana/pr_out_add_strict_checks_with_vet_golint_and_gofmt 2015-03-09 16:19:09 -07:00
Harshavardhana b952855779 Add strict checks with vet, golint and gofmt 2015-03-09 16:17:38 -07:00
Harshavardhana d02fb75dfd Merge pull request #277 from harshavardhana/pr_out_simplify_fs_codebase_split_them_into_separate_files_and_more_commenting 2015-03-08 18:05:52 -07:00
Harshavardhana 41653774fc Simplify fs codebase, split them into separate files and more commenting 2015-03-08 18:01:48 -07:00
Harshavardhana f4271e1114 Merge pull request #276 from harshavardhana/pr_out_make_bucketpolicy_strictly_typed 2015-03-08 15:58:57 -07:00
Harshavardhana 01e98eb326 Make BucketPolicy strictly typed 2015-03-08 15:57:20 -07:00
Harshavardhana 7b57797455 Merge pull request #275 from harshavardhana/pr_out_add_delimiter_and_prefix_tests_also_add_inmemory_to_support_delimiters 2015-03-08 14:53:12 -07:00
Harshavardhana 8866b2cc5f Add delimiter and prefix tests, also add inmemory to support delimiters 2015-03-08 14:51:31 -07:00
Harshavardhana f907068798 Merge pull request #273 from harshavardhana/pr_out_strict_checks_for_delimiter_and_prefix_if_absent_or_present 2015-03-08 13:02:39 -07:00
Harshavardhana 7a01db8005 Strict checks for delimiter and prefix if absent or present 2015-03-08 13:01:39 -07:00
Harshavardhana 44f02058ea Merge pull request #272 from harshavardhana/pr_out_revert_rfc1123_is_wrong_protocol_format_for_aws 2015-03-08 03:08:02 -07:00
Harshavardhana ba85ed7566 Revert "RFC1123 is wrong protocol format for AWS"
This reverts commit c7b1f8ded8.
2015-03-08 03:06:23 -07:00
Harshavardhana 54b87b483a Merge pull request #271 from harshavardhana/pr_out_rfc1123_is_wrong_protocol_format_for_aws 2015-03-08 01:56:44 -08:00
Harshavardhana c7b1f8ded8 RFC1123 is wrong protocol format for AWS 2015-03-08 01:55:25 -08:00
Harshavardhana af3037457c Merge pull request #270 from harshavardhana/pr_out_remove_redundant_uint32 2015-03-07 19:16:47 -08:00
Harshavardhana 9e89af0e3c Remove redundant uint32 2015-03-07 19:15:51 -08:00
Harshavardhana 9553eb6b4a Merge pull request #269 from harshavardhana/pr_out_get_object_metadata_needs_to_filter_based_of_prefix_when_delimiter_is_specified 2015-03-07 19:14:41 -08:00
Harshavardhana f8e2b75e23 Get object metadata needs to filter based of Prefix when delimiter is specified 2015-03-07 19:13:15 -08:00
Frederick F. Kautz IV b39eac36ea Merge pull request #268 from fkautz/pr_out_fragment_reader_implemented 2015-03-07 18:04:29 -08:00
Frederick F. Kautz IV 679c6ace3a Fragment reader implemented 2015-03-07 18:04:20 -08:00
Harshavardhana df69038b04 Merge pull request #267 from harshavardhana/pr_out_add_md5_support_for_fsstorage_also_re_purpose_getobjectmetadata_for_listobjects 2015-03-07 17:16:00 -08:00
Harshavardhana 4751ed0e30 Add MD5 support for fsStorage, also re-purpose GetObjectMetadata for ListObjects 2015-03-07 17:15:00 -08:00
Frederick F. Kautz IV 1ec0cd6683 Merge pull request #266 from fkautz/pr_out_adding_read_header_for_erasure 2015-03-07 15:54:17 -08:00
Frederick F. Kautz IV ca1a4b616c Adding read header for erasure 2015-03-07 15:53:41 -08:00
Frederick F. Kautz IV 00381c887a Adding erasure package to wrap versioned erasure. Ensures we always write latest version. 2015-03-07 13:04:02 -08:00
Harshavardhana 0658889d33 Merge pull request #264 from harshavardhana/pr_out_clang_lacks_proper_gas_support_implement_stubs_for_sha256_sha512_for_darwin 2015-03-07 02:56:42 -08:00
Harshavardhana bf5a314144 clang lacks proper gas support, implement stubs for sha256,sha512 for darwin.
REF: http://llvm.org/bugs/show_bug.cgi?id=18918
2015-03-07 02:55:48 -08:00
Harshavardhana 43f3866842 Merge pull request #263 from harshavardhana/pr_out_if_incoming_request_ip_bucketfromhostname_needs_to_be_empty_string 2015-03-07 02:53:46 -08:00
Harshavardhana 1637138f86 If incoming request IP bucketfromHostname needs to be empty string 2015-03-07 02:53:29 -08:00
Harshavardhana 15a911c4e1 Merge pull request #262 from harshavardhana/pr_out_rename_test_data_to_testdata_go_will_ignore_it_automatically 2015-03-07 01:33:21 -08:00
Harshavardhana a18bfa2fda Rename test-data to testdata, go will ignore it automatically 2015-03-07 01:32:35 -08:00
Harshavardhana c081b7c011 Merge pull request #261 from harshavardhana/pr_out_move_pkg_storage_erasure_to_pkg_encoding_erasure 2015-03-07 00:18:00 -08:00
Harshavardhana d992bccd9a Move pkg/storage/erasure to pkg/encoding/erasure - and other cleanups 2015-03-07 00:16:48 -08:00
Frederick F. Kautz IV 80fa38a41f Merge pull request #260 from fkautz/pr_out_erasure_layer_now_writes_using_new_technique 2015-03-06 16:37:59 -08:00
Frederick F. Kautz IV 856e0100c0 Erasure layer now writes using new technique 2015-03-06 16:37:44 -08:00
Harshavardhana 15552a59f9 Merge pull request #259 from harshavardhana/pr_out_now_able_to_use_crc32c_and_sha1_on_darwin_with_osx_specific_code 2015-03-06 02:39:14 -08:00
Harshavardhana 856b7680df Now able to use crc32c and sha1 on Darwin, with OSX specific code 2015-03-06 02:38:29 -08:00
Harshavardhana 46eb2eaeb9 Merge pull request #258 from harshavardhana/pr_out_further_fixes_ 2015-03-06 02:06:32 -08:00
Harshavardhana e5af8a3f5d Further fixes -
- All test files have been renamed to their respective <package>_test name,
    this is done in accordance with
      - https://github.com/golang/go/wiki/CodeReviewComments#import-dot
        imports are largely used in testing, but to avoid namespace collision
        and circular dependencies

  - Never use _* in package names other than "_test" change fragment_v1 to expose
    fragment just like 'gopkg.in/check.v1'
2015-03-06 02:04:21 -08:00
Harshavardhana 02ccf123c9 Merge pull request #257 from harshavardhana/pr_out_update_contributing_guide 2015-03-05 23:39:25 -08:00
Harshavardhana c00d1461b9 Golint cleanup from top level 2015-03-05 23:37:37 -08:00
Harshavardhana 540723d7ae Golint cleanup pkg/api 2015-03-05 21:09:19 -08:00
Harshavardhana 76e601b26b Golint cleanup pkg/storage 2015-03-05 21:09:19 -08:00
Harshavardhana 256faddab5 Golint cleanup utils/crypto/sha*,cpu,md5 2015-03-05 21:09:19 -08:00
Harshavardhana 66e31445ff Golint cleanup pkg/utils/crypto/keys 2015-03-05 21:09:19 -08:00
Harshavardhana b33e2d2f9b Golint cleanup pkg/utils/config 2015-03-05 21:09:19 -08:00
Harshavardhana 861f13d5bd Golint cleanup pkg/utils/cpu 2015-03-05 21:09:19 -08:00
Harshavardhana c36450a83a Golint cleanup pkg/utils/policy 2015-03-05 21:09:19 -08:00
Harshavardhana 3e321b6631 Golint cleanup pkg/utils/split 2015-03-05 21:09:19 -08:00
Frederick F. Kautz IV 237921338a Merge pull request #256 from fkautz/pr_out_fragment_now_implements_new_version 2015-03-05 20:56:13 -08:00
Frederick F. Kautz IV 1186c47603 Fragment now implements new version 2015-03-05 20:56:02 -08:00
Frederick F. Kautz IV e6db550fdc Merge pull request #255 from fkautz/pr_out_renaming_donut_packages_to_match_layout 2015-03-05 19:44:56 -08:00
Frederick F. Kautz IV 665af44c70 Renaming donut packages to match layout 2015-03-05 19:44:01 -08:00
Frederick F. Kautz IV 15b26c5134 Merge pull request #254 from fkautz/pr_out_removing_innerxml 2015-03-04 14:25:18 -08:00
Frederick F. Kautz IV 6ec7894312 Removing innerxml 2015-03-04 14:24:56 -08:00
Frederick F. Kautz IV 862fc31d56 Merge pull request #253 from fkautz/pr_out_updating_godeps_goversion_and_packages 2015-03-04 12:52:25 -08:00
Frederick F. Kautz IV 8d40f60e7d Updating godeps GoVersion and Packages 2015-03-04 12:52:02 -08:00
Frederick F. Kautz IV 5155b2f124 Merge pull request #252 from fkautz/pr_out_fixing_xml_tags
Fixing xml tags
2015-03-04 12:51:22 -08:00
Frederick F. Kautz IV 6f7840677a Fixing xml tags 2015-03-04 11:02:37 -08:00
Harshavardhana 4bdfe61701 Merge pull request #251 from harshavardhana/pr_out_handle_individual_objects_too 2015-03-04 01:54:44 -08:00
Harshavardhana f2e238199b Handle individual objects too 2015-03-04 01:54:35 -08:00
Harshavardhana cb46c61be4 Merge pull request #250 from harshavardhana/pr_out_add_proper_path_prefix_to_be_delimited 2015-03-04 00:57:00 -08:00
Harshavardhana e400e85639 Add proper path prefix to be delimited 2015-03-04 00:54:39 -08:00
Harshavardhana df135d7307 Merge pull request #249 from harshavardhana/pr_out_pathprefix_is_filtered_out_properly_and_delimited_as_well 2015-03-03 23:08:30 -08:00
Harshavardhana cc46475c86 Pathprefix is filtered out properly and delimited as well 2015-03-03 19:45:54 -08:00
Frederick F. Kautz IV ae9a0ea6fb Merge pull request #248 from fkautz/pr_out_renaming_package_to_gopackage_to_fix_golint_error 2015-03-03 12:57:06 -08:00
Frederick F. Kautz IV 34c1e58332 Renaming Package to goPackage to fix golint error 2015-03-03 12:56:19 -08:00
Frederick F. Kautz IV 3e4509efeb Merge pull request #247 from fkautz/pr_out_renaming_variable_to_pass_golint 2015-03-03 12:01:41 -08:00
Frederick F. Kautz IV f4eed73d4e Renaming variable to pass golint 2015-03-03 12:01:14 -08:00
Harshavardhana a2bdc9df7e Merge pull request #246 from harshavardhana/pr_out_janitor_duty_v2 2015-03-03 02:44:42 -08:00
Harshavardhana 0ebaac3594 Janitor duty v2 2015-03-03 02:43:24 -08:00
Harshavardhana 3db32f4935 Merge pull request #245 from harshavardhana/pr_out_force_exported_functions_to_have_comments 2015-03-03 02:41:24 -08:00
Harshavardhana 3a3c8645fc Update comments across the codebase 2015-03-03 02:39:38 -08:00
Harshavardhana 137584d658 Add comments 2015-03-03 01:25:45 -08:00
Harshavardhana 721ec9ef5a Force exported functions to have comments 2015-03-03 01:01:38 -08:00
Harshavardhana 3d158b1240 Merge pull request #244 from harshavardhana/pr_out_add_deadcode_code_which_recursivley_goes_into_all_directories_and_verifies_dangling_variables 2015-03-02 18:44:34 -08:00
Harshavardhana c3ad0906e0 Add deadcode code which recursivley goes into all directories and verifies dangling variables. 2015-03-02 18:44:20 -08:00
Frederick F. Kautz IV 022b89dd9b Merge pull request #243 from fkautz/pr_out_renaming_appendustr_to_appenduniqstr 2015-03-01 17:06:19 -08:00
Frederick F. Kautz IV 32f8c17174 Renaming AppendUstr to AppendUniqStr 2015-03-01 17:06:00 -08:00
Anand Babu (AB) Periasamy 81ede6c3fe Merge pull request #241 from abperiasamy/janitor
On janitor duty.
2015-03-01 16:43:04 -08:00
Frederick F. Kautz IV 7ee3017a1c Merge pull request #242 from fkautz/pr_out_renaming_appenduint_to_appenduniqint 2015-03-01 16:39:55 -08:00
Frederick F. Kautz IV de6131cc7c Renaming AppendUInt to AppendUniqInt 2015-03-01 16:39:45 -08:00
Anand Babu (AB) Periasamy d9c9634138 removed custom Assert 2015-03-01 15:28:42 -08:00
Frederick F. Kautz IV 60454c53a2 Merge pull request #239 from fkautz/pr_out_adding_test_at_byte_level 2015-03-01 15:15:21 -08:00
Frederick F. Kautz IV 6f300c9ef0 Adding test at byte level 2015-03-01 15:13:09 -08:00
Anand Babu (AB) Periasamy 177121868b removed HomeDir 2015-03-01 15:13:08 -08:00
Frederick F. Kautz IV cd22304afb Merge pull request #238 from fkautz/pr_out_specifying_more_exact_types_for_data 2015-03-01 14:43:20 -08:00
Frederick F. Kautz IV 0b08312ddd Specifying more exact types for data 2015-03-01 14:43:11 -08:00
Harshavardhana ed4bca240f Merge pull request #237 from harshavardhana/pr_out_add_tests_add_newheader_for_populating_header_and_validateheader_ 2015-03-01 13:21:26 -08:00
Harshavardhana 9f43659135 Add tests, add NewHeader() for populating Header and ValidateHeader() 2015-03-01 13:19:06 -08:00
Anand Babu (AB) Periasamy 6515678e87 Merge pull request #236 from fkautz/pr_out_adding_data_writer
Adding data writer
2015-03-01 11:36:35 -08:00
Frederick F. Kautz IV 7414dc9b75 Adding data writer 2015-03-01 11:32:30 -08:00
Harshavardhana 359af56397 Merge pull request #235 from harshavardhana/pr_out_move_appendustr_appenduint_into_helpers 2015-03-01 11:19:40 -08:00
Harshavardhana eb9a4a83ac Move AppendUstr(), AppendUint() into helpers 2015-03-01 11:19:03 -08:00
Frederick F. Kautz IV 9fb67c4195 Merge pull request #234 from fkautz/pr_out_changing_k_and_m_in_data_go_to_match_new_datatype_in_erasure_package 2015-03-01 01:28:43 -08:00
Frederick F. Kautz IV be12a6b3d9 Changing K and M in data.go to match new datatype in erasure package 2015-03-01 01:28:33 -08:00
Harshavardhana 33601ff567 Merge pull request #233 from harshavardhana/pr_out_make_k_m_to_be_uint8_and_technique_becomes_its_own_type 2015-03-01 01:26:42 -08:00
Harshavardhana b77c62e25d Make K,M to be uint8 and Technique becomes its own type 2015-03-01 01:25:28 -08:00
Frederick F. Kautz IV c290b360e4 Merge pull request #232 from fkautz/pr_out_making_changes_to_data_based_on_discussion 2015-03-01 01:18:11 -08:00
Frederick F. Kautz IV bb0441917c Making changes to data based on discussion 2015-03-01 01:16:22 -08:00
Harshavardhana 1f574d19fc Merge pull request #231 from harshavardhana/pr_out_avoid_allocating_1gig_memory_avoid_such_mistakes 2015-03-01 00:44:05 -08:00
Harshavardhana 2f04a1299e Avoid allocating 1gig memory, avoid such mistakes 2015-03-01 00:43:12 -08:00
Frederick F. Kautz IV 91c48e8d73 Merge pull request #230 from fkautz/pr_out_adding_data_go_does_nothing_for_now 2015-03-01 00:28:15 -08:00
Frederick F. Kautz IV 2916b1278e Adding data.go, does nothing for now. 2015-03-01 00:27:52 -08:00
Frederick F. Kautz IV 9d30475f00 Merge pull request #229 from fkautz/pr_out_donut_frame_is_now_its_own_package 2015-03-01 00:02:35 -08:00
Frederick F. Kautz IV b4ef522a9b Donut frame is now its own package 2015-03-01 00:02:14 -08:00
Frederick F. Kautz IV 97e572f318 Merge pull request #228 from fkautz/pr_out_renaming_write_to_writeframe 2015-02-28 23:53:06 -08:00
Frederick F. Kautz IV 6c2428833a Renaming Write to WriteFrame 2015-02-28 23:52:56 -08:00
Harshavardhana 8ab0cc29f2 Merge pull request #227 from harshavardhana/pr_out_add_donut_benchmark_for_64mb_128mb_256mb_512mb 2015-02-28 17:06:40 -08:00
Harshavardhana 6b397844b9 Add donut benchmark for 64MB, 128MB, 256MB, 512MB
Current average values

~~~
> minio/pkg/storage/donut/v1 *> go test -bench .
OK: 2 passed
PASS
BenchmarkDonut64M              5         266249634 ns/op         252.05 MB/s
BenchmarkDonut128M             3         436507394 ns/op         307.48 MB/s
BenchmarkDonut256M             2         836116359 ns/op         321.05 MB/s
BenchmarkDonut512M             1        1676738951 ns/op         320.19 MB/s
ok      github.com/minio-io/minio/pkg/storage/donut/v1  8.430s
> minio/pkg/storage/donut/v1 *>
~~~
2015-02-28 17:05:46 -08:00
Harshavardhana 24c5ab70be Merge pull request #226 from harshavardhana/pr_out_donut_gen_works_with_new_donut_frame 2015-02-28 16:30:34 -08:00
Harshavardhana 65f22083ca donut_gen works with new Donut Frame 2015-02-28 16:30:18 -08:00
Frederick F. Kautz IV 4d98c355c9 Merge pull request #224 from abperiasamy/units 2015-02-28 16:12:10 -08:00
Frederick F. Kautz IV a067fdb59d Merge pull request #225 from fkautz/pr_out_donut_now_tests_amount_written_should_match_expected_amount_to_write 2015-02-28 16:10:09 -08:00
Frederick F. Kautz IV ddc7cf835e Donut now tests amount written should match expected amount to write 2015-02-28 16:09:52 -08:00
Frederick F. Kautz IV a86e5b5586 Merge pull request #223 from fkautz/pr_out_updating_comment_describing_data_type 2015-02-28 16:00:12 -08:00
Frederick F. Kautz IV d3d1205eb1 Updating comment describing data type 2015-02-28 15:59:52 -08:00
Frederick F. Kautz IV c2ae974c94 Merge pull request #222 from fkautz/pr_out_new_donut_frame_implemented 2015-02-28 15:54:45 -08:00
Frederick F. Kautz IV 58a04ee831 New donut frame implemented 2015-02-28 15:54:13 -08:00
Anand Babu (AB) Periasamy 317a1141c0 removed unitconv 2015-02-28 15:53:44 -08:00
Frederick F. Kautz IV 9744efc725 Merge pull request #221 from fkautz/pr_out_adding_streaming_sha512 2015-02-28 15:52:10 -08:00
Frederick F. Kautz IV 90cd8b7b47 Adding streaming sha512 2015-02-28 15:51:33 -08:00
Harshavardhana 56bd413a16 Merge pull request #219 from harshavardhana/pr_out_add_1mb_block_benchmarks 2015-02-28 15:25:24 -08:00
Harshavardhana 7feca3f0d1 Add 1MB block benchmarks 2015-02-28 15:00:24 -08:00
Harshavardhana 20dc738b67 Merge pull request #218 from harshavardhana/pr_out_implement_proper_delimiter_and_prefix_handling 2015-02-28 14:48:46 -08:00
Harshavardhana 0c2d58bc6d Implement proper delimiter and prefix handling
With this change Minio server now responds with, delimited
'object names' in conjunction with prefix filtering

~~~
<ListBucketResult>
  <Name>example-bucket</Name>
  <Prefix></Prefix>
  <Marker></Marker>
  <MaxKeys>1000</MaxKeys>
  <Delimiter>/</Delimiter>
  <IsTruncated>false</IsTruncated>
  <Contents>
    <Key>sample.html</Key>
    <LastModified>2011-02-26T01:56:20.000Z</LastModified>
    <ETag>example-bucket#sample.html</ETag>
    <Size>142863</Size>
    <Owner>
      <ID>minio</ID>
      <DisplayName>minio</DisplayName>
    </Owner>
    <StorageClass>STANDARD</StorageClass>
  </Contents>
  <CommonPrefixes>
    <Prefix>photos/</Prefix>
  </CommonPrefixes>
</ListBucketResult>
~~~

~~~
<ListBucketResult>
  <Name>example-bucket</Name>
  <Prefix>photos/2006/</Prefix>
  <Marker></Marker>
  <MaxKeys>1000</MaxKeys>
  <Delimiter>/</Delimiter>
  <IsTruncated>false</IsTruncated>

  <CommonPrefixes>
    <Prefix>photos/2006/feb/</Prefix>
  </CommonPrefixes>
  <CommonPrefixes>
    <Prefix>photos/2006/jan/</Prefix>
  </CommonPrefixes>
</ListBucketResult>
~~~
2015-02-28 14:47:19 -08:00
Harshavardhana acee4d16fd Merge pull request #217 from harshavardhana/pr_out_use_validstring 2015-02-27 19:49:33 -08:00
Harshavardhana d5e5a3b3e6 Use validString 2015-02-27 19:49:18 -08:00
Harshavardhana 27fab98bf9 Merge pull request #216 from harshavardhana/pr_out_add_object_name_validation 2015-02-27 19:42:14 -08:00
Harshavardhana 6ebb48b4ea Add object name validation 2015-02-27 19:42:04 -08:00
Harshavardhana e7992320c1 Merge pull request #215 from harshavardhana/pr_out_sort_list_of_objects 2015-02-27 17:53:19 -08:00
Harshavardhana 9acb1f728c Sort list of objects 2015-02-27 17:52:55 -08:00
Harshavardhana 3a048dc676 Merge pull request #208 from harshavardhana/pr_out_implement_delimiter_and_path_prefix 2015-02-27 16:24:15 -08:00
Harshavardhana 53669a0854 Implement delimiter, path prefix 2015-02-27 16:23:05 -08:00
Harshavardhana 01e84c596c Merge pull request #214 from harshavardhana/pr_out_remove_donut_gen_binary_and_update_crc32c_function 2015-02-27 14:42:22 -08:00
Harshavardhana 3f8b3462e6 Remove donut_gen binary and update crc32c function 2015-02-27 14:41:53 -08:00
Harshavardhana 9aea7fd97b Merge pull request #213 from harshavardhana/pr_out_crc32c_re_implementation_with_convenience_functions 2015-02-27 14:35:11 -08:00
Harshavardhana 8ce9b84b69 Crc32c re-implementation with Convenience functions
- Sum32([]byte) --> uint32
   - Sum(io.Reader) --> uint32, error
2015-02-27 13:39:17 -08:00
Frederick F. Kautz IV 2e37791681 Merge pull request #212 from fkautz/pr_out_adding_comparison_for_footer_s_inim 2015-02-27 12:40:10 -08:00
Frederick F. Kautz IV a42872d557 Merge pull request #211 from fkautz/pr_out_moving_donut_gen_to_its_own_dir_and_renaming_it_as_donut_gen_v1 2015-02-27 12:40:07 -08:00
Frederick F. Kautz IV 1f7a3c13a5 Adding comparison for footer's INIM 2015-02-27 12:39:52 -08:00
Frederick F. Kautz IV 2ca62f13a5 Moving donut_gen to its own dir and renaming it as donut_gen_v1 2015-02-27 12:39:14 -08:00
Frederick F. Kautz IV 22ddc3dcbb Merge pull request #210 from fkautz/pr_out_seek_to_beginning_for_tempbuffer 2015-02-27 12:18:58 -08:00
Frederick F. Kautz IV be768d01a2 Seek to beginning for tempbuffer 2015-02-27 12:18:27 -08:00
Frederick F. Kautz IV da10fd5a83 Merge pull request #209 from fkautz/pr_out_adding_crc32c_to_write 2015-02-26 23:04:57 -08:00
Frederick F. Kautz IV 5c52da6ebe Adding crc32c to write 2015-02-26 23:04:07 -08:00
Anis Elleuch e4b6239277 Add Dockerfile to build a docker image with embarked minio server 2015-02-26 22:53:30 +01:00
Harshavardhana 1786408bcc Merge pull request #206 from harshavardhana/pr_out_remove_http_server_timeouts_write_and_read 2015-02-24 13:56:56 -08:00
Harshavardhana a9aaff0ee0 Remove HTTP server timeouts write and read.
Implement it later with a proper timer thread. Large file
transfers from 'mc' fail with i/o timeout without this change.
2015-02-24 13:55:24 -08:00
Frederick F. Kautz IV e0d78e7381 Merge pull request #205 from fkautz/pr_out_making_donut_use_io_readwriteseek_instead_of_io_writer 2015-02-23 20:27:37 -08:00
Frederick F. Kautz IV ef442289da Making donut use io.ReadWriteSeek instead of io.Writer 2015-02-23 20:27:25 -08:00
Harshavardhana 0f45e17505 Merge pull request #204 from harshavardhana/pr_out_add_bitdeli_badge_and_expose_analytics_beacon 2015-02-23 18:06:19 -08:00
Harshavardhana 3348b79eb8 Add bitdeli badge and expose Analytics beacon 2015-02-23 18:05:58 -08:00
Harshavardhana 182d614bdd Merge pull request #203 from harshavardhana/pr_out_more_updates_on_documentation 2015-02-23 17:45:16 -08:00
Harshavardhana 5e1e5ad786 More updates on documentation 2015-02-23 17:44:55 -08:00
Harshavardhana 2b8adef454 Merge pull request #202 from harshavardhana/pr_out_update_minioapi_documentation 2015-02-23 16:46:57 -08:00
Harshavardhana b7868d23ac Update minioapi documentation 2015-02-23 16:46:48 -08:00
Harshavardhana 0c36dc24f5 Merge pull request #201 from harshavardhana/pr_out_update_erasure_documentation 2015-02-23 13:39:30 -08:00
Harshavardhana f4b5519451 Update erasure documentation 2015-02-23 13:39:16 -08:00
Harshavardhana 3b3e446102 Merge pull request #200 from abperiasamy/reorg
Reorg
2015-02-23 13:12:13 -08:00
Anand Babu (AB) Periasamy 6fc11932ec make test -> test-all 2015-02-23 11:03:40 -08:00
Anand Babu (AB) Periasamy de41e465c8 move httpserver under server 2015-02-23 11:03:01 -08:00
Harshavardhana 7c608ec857 Merge pull request #199 from harshavardhana/pr_out_fix_a_typo 2015-02-23 02:30:43 -08:00
Harshavardhana baa1719ed2 Fix a typo 2015-02-23 02:30:36 -08:00
Harshavardhana 40014b8391 Merge pull request #198 from harshavardhana/pr_out_add_domain_and_subdomain_support_for_minioapi 2015-02-23 02:28:18 -08:00
Harshavardhana 51e80eaa6d Add domain and subdomain support for MinioAPI
This change brings in domain and subdomain support

   - ./minio --domain "yourminiodomain.com"

This change brings in a much needed feature by keeping
bucketnames as part of your 'DNS' name.

All your existing applications can be migrated off from s3 to
Minio without little to no modifications.

NOTE: Setting up DNS for your `buckets` is out of scope of this feature
2015-02-23 02:25:01 -08:00
Harshavardhana 2d3b00b831 Merge pull request #197 from harshavardhana/pr_out_purge_tiedot_wrapper 2015-02-22 20:04:42 -08:00
Harshavardhana a92c6cb2b2 Purge tiedot wrapper 2015-02-22 20:02:09 -08:00
Harshavardhana 8d9613646f Merge pull request #196 from harshavardhana/pr_out_remove_setup_development_environment_script 2015-02-21 21:39:37 -08:00
Harshavardhana a3fe948c8b Remove setup development environment script 2015-02-21 21:38:04 -08:00
Harshavardhana 87bca64173 Merge pull request #195 from harshavardhana/pr_out_add_license_header_for_minio_modifications_improvements_for_sha1_sha256_sha512_implementations 2015-02-21 15:54:02 -08:00
Harshavardhana 49a714d1a4 Add license header for Minio modifications, improvements for sha1,sha256,sha512 implementations
Also bring in SSE3 optimized public domain implementation of SHA1 from Intel ``FIPS PUB 180-1``
2015-02-21 15:50:47 -08:00
Harshavardhana cfb1fe7f9d Merge pull request #194 from harshavardhana/pr_out_implement_sha1_as_intel_optimized_set 2015-02-21 11:27:07 -08:00
Harshavardhana 12cff1be58 Implement sha1 as intel optimized set 2015-02-21 11:25:09 -08:00
Harshavardhana e2bc6c8b27 Merge pull request #193 from vadmeste/fix_sha256_faulty_computation
Add missing asm instruction to correct sha256 calculation in avx mode
2015-02-21 10:49:49 -08:00
Anis Elleuch 1d4d7ff274 Add missing asm instruction to correct sha256 calculation in avx mode 2015-02-21 19:34:36 +01:00
Harshavardhana 121379c992 Merge pull request #192 from vadmeste/add_intel_sha256_optimized_algo
Use Intel optimized code (ssse3, avx, avx2) to calculate sha256
2015-02-21 08:35:59 -08:00
Anis Elleuch e89271b8f5 Use Intel optimized code (ssse3, avx, avx2) to calculate sha256 2015-02-21 13:11:15 +01:00
Harshavardhana 3d70b96ae9 Merge pull request #191 from harshavardhana/pr_out_add_proper_entries_for_gobheader_data_copy 2015-02-21 01:45:41 -08:00
Harshavardhana 3151f9b6c3 Add proper entries for GobHeader, Data copy.
This commit also adds 'donut_gen.go' for generating sample donut file
2015-02-21 01:44:27 -08:00
Frederick F. Kautz IV 4db9b5a348 Merge pull request #189 from fkautz/pr_out_writing_data_out_with_error_handling 2015-02-20 23:24:11 -08:00
Frederick F. Kautz IV 8129d8fd0b Writing data out with error handling 2015-02-20 23:24:01 -08:00
Frederick F. Kautz IV 97b2e7fb3b Merge pull request #188 from fkautz/pr_out_moving_donut_code_to_v1_in_donut_package 2015-02-20 23:07:50 -08:00
Frederick F. Kautz IV 98ddbd840e Moving donut code to v1 in donut package 2015-02-20 23:07:43 -08:00
Frederick F. Kautz IV 005ad1a9e1 Merge pull request #187 from fkautz/pr_out_fixing_magic_number_for_inim 2015-02-20 22:43:19 -08:00
Frederick F. Kautz IV 9833647fb7 Fixing magic number for INIM 2015-02-20 22:42:58 -08:00
Frederick F. Kautz IV 339fa40b21 Merge pull request #186 from abperiasamy/donut-magic 2015-02-20 19:15:11 -08:00
Anand Babu (AB) Periasamy ec36a598c9 Magic as numbers are faster to encode and compare 2015-02-20 18:20:21 -08:00
Harshavardhana eab19e3ce4 Merge pull request #185 from harshavardhana/pr_out_remove_go_cover 2015-02-20 17:44:46 -08:00
Harshavardhana 741e14f749 Remove go cover and remove unncessary Makefiles 2015-02-20 17:44:26 -08:00
Harshavardhana afe7293aef Merge pull request #184 from harshavardhana/pr_out_sha512_implemention_with_intel_assembly_code 2015-02-20 16:34:01 -08:00
Harshavardhana 19a4998fcb SHA512 Implemention with Intel assembly code 2015-02-20 16:32:19 -08:00
Harshavardhana a552800dcc Merge pull request #183 from harshavardhana/pr_out_osx_compatibility_update_for_checkdeps_sh 2015-02-20 00:30:31 -08:00
Harshavardhana cdd43a11be OSX compatibility update for checkdeps.sh 2015-02-20 00:28:35 -08:00
Harshavardhana 83c636c80c Merge pull request #182 from harshavardhana/pr_out_add_donut_tests_just_for_verification 2015-02-18 19:46:39 -08:00
Harshavardhana c4f0aad9b5 Add donut tests, just for verification 2015-02-18 19:46:14 -08:00
Frederick F. Kautz IV aa2c622f52 Merge pull request #181 from fkautz/pr_out_donut_structure_refined 2015-02-18 17:18:44 -08:00
Frederick F. Kautz IV f7f34d08e8 Donut structure refined 2015-02-18 17:18:33 -08:00
Frederick F. Kautz IV ab80c0ce12 Merge pull request #180 from abperiasamy/donut 2015-02-18 15:57:16 -08:00
Anand Babu (AB) Periasamy 9e304b53de donut spec v1 prototype 2015-02-18 15:52:12 -08:00
Harshavardhana 49de6e0605 Merge pull request #179 from harshavardhana/pr_out_remove_govet_dependency_for_now 2015-02-18 15:51:42 -08:00
Harshavardhana 0a1a47da1b remove govet dependency for now 2015-02-18 15:51:31 -08:00
Harshavardhana 1dc14bccfe Merge pull request #178 from harshavardhana/pr_out_run_govet_and_fix 2015-02-18 15:34:26 -08:00
Harshavardhana fab954f13f Run govet and fix 2015-02-18 15:33:55 -08:00
Harshavardhana 1b1371ffec Merge pull request #177 from harshavardhana/pr_out_no_symlink_fail_when_not_in_gopath 2015-02-18 14:36:33 -08:00
Harshavardhana 79455c3f9d No symlink, fail when not in GOPATH 2015-02-18 14:35:49 -08:00
Harshavardhana 2bc7ded828 Merge pull request #176 from harshavardhana/pr_out_some_more_cleanup 2015-02-18 12:16:34 -08:00
Harshavardhana f7a06a5d1e Some more cleanup 2015-02-18 12:15:33 -08:00
Frederick F. Kautz IV 784ab9a551 Merge pull request #175 from fkautz/pr_out_adding_header_version 2015-02-18 10:21:40 -08:00
Frederick F. Kautz IV 05ac09bf69 Adding header version 2015-02-18 10:21:02 -08:00
Harshavardhana c212ae18bc Merge pull request #174 from harshavardhana/pr_out_no_need_to_check_pip_fixes_172 2015-02-18 01:24:10 -08:00
Harshavardhana 2a5183ff8a No need to check pip fixes #172 2015-02-18 01:23:07 -08:00
Harshavardhana d8e0be7575 Merge pull request #173 from harshavardhana/pr_out_make_channels_more_aware_of_errors_and_shutdown_on_error_some_cleanup 2015-02-18 00:24:35 -08:00
Harshavardhana a3e5121f7b Make channels more aware of errors and shutdown on error - some cleanup 2015-02-18 00:24:19 -08:00
Harshavardhana 4bdbfe47a2 Merge pull request #171 from harshavardhana/pr_out_expose_policy_code_for_api_router_usage 2015-02-17 19:06:14 -08:00
Harshavardhana cf6d03b907 Expose policy code, for api router usage 2015-02-17 19:06:01 -08:00
Harshavardhana 5235badec9 Merge pull request #169 from harshavardhana/pr_out_add_policy_validation_code_more_rigorous 2015-02-17 18:10:00 -08:00
Harshavardhana 650b3bac9b Merge pull request #168 from vadmeste/fix_devscripts_headers 2015-02-17 18:09:51 -08:00
Frederick F. Kautz IV 2af664eeaf Merge pull request #170 from fkautz/pr_out_adding_scaffolding_for_writing_donut 2015-02-17 17:51:54 -08:00
Frederick F. Kautz IV fe9a5c14a0 Adding scaffolding for writing donut 2015-02-17 17:47:10 -08:00
Harshavardhana 980d229272 Add policy validation code more rigorous 2015-02-17 13:23:16 -08:00
Anis Elleuch 04075b15c9 Fix Shebang position
Add licence to setup_development_environment.sh
2015-02-17 19:17:31 +01:00
Harshavardhana 7882c8c746 Merge pull request #167 from harshavardhana/pr_out_add_new_error_response 2015-02-16 20:44:41 -08:00
Harshavardhana 2696d2f4e7 Add new error response 2015-02-16 20:44:25 -08:00
Harshavardhana 45866ff3a7 Merge pull request #166 from harshavardhana/pr_out_skip_policy_files 2015-02-16 18:37:18 -08:00
Harshavardhana f04beab7c2 Skip policy files 2015-02-16 18:37:09 -08:00
Harshavardhana 47a5dd7e72 Merge pull request #165 from vadmeste/more_check_for_call_results 2015-02-16 18:30:28 -08:00
Harshavardhana 4ce180bb72 Merge pull request #164 from harshavardhana/pr_out_implement_bucket_policy_handler 2015-02-16 18:28:48 -08:00
Harshavardhana eeae64935e Implement bucket policy handler and with galore of cleanup 2015-02-16 18:20:40 -08:00
Anis Elleuch dc551e6c2e Check function return values for downloading operations
Fix two regressions after changing the behavior of check_version
call function returns the status code of the first part of the pipe command
Fix indentation
Add more error msgs when git fails
MINIO_DEV takes the directory path where the env.sh is found
2015-02-16 22:29:49 +01:00
Harshavardhana 7d8c34e055 Merge pull request #163 from harshavardhana/pr_out_add_osx_deps_check_and_development_environment 2015-02-15 15:20:34 -08:00
Harshavardhana 574ee2a271 Add osx deps check and development environment 2015-02-15 14:48:11 -08:00
Harshavardhana 6af37d5ca1 Merge pull request #162 from vadmeste/installer_script_enhancements 2015-02-15 14:19:37 -08:00
Anis Elleuch f95b954b9a Add INT signal handler to accelerate quitting when asked by the user
Print the required version of the missing packages
Check the status code of curl download and abort when failed
2015-02-15 23:05:10 +01:00
Harshavardhana be9f59c555 Merge pull request #161 from harshavardhana/pr_out_add_license_and_fix_development_scripts 2015-02-15 02:01:35 -08:00
Harshavardhana ba3e2d41f7 Add license and fix development scripts 2015-02-15 01:59:48 -08:00
Harshavardhana 78755aa1e0 Merge pull request #160 from harshavardhana/pr_out_move_to_devscripts_to_avoid_top_level_dir_clutter 2015-02-14 17:29:38 -08:00
Harshavardhana 0d91e7d540 Move to devscripts to avoid top level dir clutter 2015-02-14 17:28:55 -08:00
Harshavardhana 5a2616ca47 Merge pull request #159 from harshavardhana/pr_out_further_changes_to_minio_dev_script 2015-02-14 17:23:09 -08:00
Harshavardhana 6b85cb1168 Further changes to minio dev script 2015-02-14 17:21:29 -08:00
Harshavardhana 58dcd5751e Merge pull request #156 from vadmeste/add_minio_env_installer 2015-02-14 17:12:15 -08:00
Anis Elleuch 6e30ccd612 * Add a development environnment installer for minio project with an automatic dependency installation
* Install minio in /home/vadmeste/minio-dev by default
* Check for host architecutre before installing
* Check the minio dev directory before start
* env.sh is always in the root of minio-dev directory, use base dirname instead of hardcoded path
* Explain why we use main function in the script
* env.sh should not mess with GOROOT variable if already defined
* Force the user to set GOROOT var if golang is already installed
* Prettify the script output
* Hide pushd/popd output
2015-02-14 22:06:29 +01:00
Harshavardhana 685077eaa5 Merge pull request #158 from harshavardhana/pr_out_there_is_no_golang_version_1_4_0 2015-02-13 19:10:25 -08:00
Harshavardhana cce10456d5 There is no golang version 1.4.0 2015-02-13 19:10:15 -08:00
Harshavardhana be1b50247a Merge pull request #157 from harshavardhana/pr_out_reorg_docs_and_cleanup 2015-02-13 19:07:06 -08:00
Harshavardhana f07ccb035d Reorg docs and cleanup 2015-02-13 19:06:47 -08:00
Harshavardhana a527251865 Merge pull request #155 from harshavardhana/pr_out_update_docs 2015-02-13 15:26:48 -08:00
Harshavardhana bd56b6e571 Update docs 2015-02-13 15:26:26 -08:00
Harshavardhana 16c520639f Merge pull request #154 from harshavardhana/pr_out_write_error_responses_documentation 2015-02-13 15:21:16 -08:00
Harshavardhana 5a0a700a45 Write Error Responses documentation 2015-02-13 15:20:58 -08:00
Harshavardhana 08c6717f88 Merge pull request #153 from vadmeste/check_for_golang_version 2015-02-13 02:59:16 -08:00
Anis Elleuch 262d8cc23a Check if the installed golang version is greater than 1.4.0 2015-02-13 10:09:15 +01:00
Anis Elleuch 2ef1df016b Add a generic version checker function 2015-02-13 10:08:52 +01:00
Harshavardhana e0b9a2f9ef Merge pull request #152 from harshavardhana/pr_out_reply_in_xml_from_validate_and_ignore_handlers 2015-02-11 22:00:53 -08:00
Harshavardhana 966cdd4f05 Reply in xml from validate and ignore handlers 2015-02-11 22:00:45 -08:00
Harshavardhana 8a562ebbef Merge pull request #151 from harshavardhana/pr_out_implement_s3_style_errorcodes_and_response 2015-02-11 21:28:22 -08:00
Harshavardhana ac4f07906c Implement S3 Style ErrorCodes and Response
This patchset also brings in lot of cleanup in terms of minioapi codebase
2015-02-11 21:27:28 -08:00
Harshavardhana 6e73ccec75 Merge pull request #149 from harshavardhana/pr_out_update_contributors_document 2015-02-09 13:34:34 -08:00
Harshavardhana 0ac611e452 Update contributors document 2015-02-09 13:34:19 -08:00
Harshavardhana b92ce76197 Merge pull request #148 from harshavardhana/pr_out_update_docs 2015-02-08 17:51:00 -08:00
Harshavardhana b12a493db8 Update Docs 2015-02-08 17:50:18 -08:00
Harshavardhana 4f43e37a73 Merge pull request #147 from harshavardhana/pr_out_restructure_docs_and_move_mkdocs_yml_to_top_level 2015-02-08 17:41:22 -08:00
Harshavardhana d036bf3a2a Restructure docs and move mkdocs.yml to top-level 2015-02-08 17:40:39 -08:00
Harshavardhana 6911310661 Merge pull request #146 from harshavardhana/pr_out_change_ports_to_9000_and_9001 2015-02-08 14:11:50 -08:00
Harshavardhana d9a97b6c86 Change ports to 9000 and 9001 2015-02-08 14:10:59 -08:00
Harshavardhana 2b1b4f2713 Merge pull request #145 from harshavardhana/pr_out_add_license_header 2015-02-08 03:00:55 -08:00
Harshavardhana 680848bdcb Add license header 2015-02-08 03:00:32 -08:00
Harshavardhana b2724b80c1 Merge pull request #144 from harshavardhana/pr_out_verify_both_x_amz_date_and_date_header_before_discarding_request 2015-02-08 02:39:03 -08:00
Harshavardhana 8087ca2450 Verify both 'x-amz-date' and 'date' header before discarding request 2015-02-08 02:37:19 -08:00
Harshavardhana 62648c8636 Merge pull request #143 from harshavardhana/pr_out_changes_to_tests_pending_from_142 2015-02-06 20:47:32 -08:00
Harshavardhana 92f83982db Changes to tests pending from #142 2015-02-06 20:47:21 -08:00
Harshavardhana 58f2c73f42 Merge pull request #142 from harshavardhana/pr_out_avoid_trailing_for_buckets_and_also_re_directs_in_accordance_with_aws_clients 2015-02-06 20:42:26 -08:00
Harshavardhana ecb70a4c19 Avoid trailing '/' for buckets and also re-directs - in accordance with aws clients 2015-02-06 20:42:09 -08:00
Harshavardhana a5bf6b7f14 Merge pull request #139 from harshavardhana/pr_out_implement_authorization_support 2015-02-06 02:09:21 -08:00
Harshavardhana 81fc11ee5d Implement authorization support 2015-02-06 02:08:52 -08:00
Harshavardhana eba86c07e9 Merge pull request #138 from harshavardhana/pr_out_ignore_eof_in_readconfig_ 2015-02-05 16:12:00 -08:00
Harshavardhana 0e8b16a55d Ignore EOF in ReadConfig() 2015-02-05 16:10:49 -08:00
Harshavardhana 829be023d2 Merge pull request #137 from harshavardhana/pr_out_reply_back_accesskey_secretkey_through_json 2015-02-05 16:00:00 -08:00
Harshavardhana 72d0999dcb Reply back AccessKey, Secretkey through json 2015-02-05 15:59:44 -08:00
Harshavardhana 95f214c99b Append to Users list 2015-02-05 15:40:51 -08:00
Harshavardhana b3b73ff4cb Merge pull request #136 from harshavardhana/pr_out_store_credentials_through_webui 2015-02-05 14:20:06 -08:00
Harshavardhana 4c90017b02 Store credentials through webui 2015-02-05 14:19:48 -08:00
Frederick F. Kautz IV 71fab1d91a Merge pull request #135 from fkautz/pr_out_content_type_is_now_passed_from_minioapi_to_storage 2015-02-05 14:05:59 -08:00
Frederick F. Kautz IV 620435cea6 Content type is now passed from minioapi to storage 2015-02-05 14:05:43 -08:00
Harshavardhana 833756138d Merge pull request #134 from harshavardhana/pr_out_create_the_non_existent_directory 2015-02-05 10:57:55 -08:00
Harshavardhana 19267fa29a Create the non-existent directory 2015-02-05 10:57:26 -08:00
Frederick F. Kautz IV 549cf6b854 Merge pull request #133 from fkautz/pr_out_adding_content_type_to_backend_storage_drivers 2015-02-04 17:37:13 -08:00
Frederick F. Kautz IV 288bc3fcc7 Adding content type to backend storage drivers 2015-02-04 17:32:40 -08:00
Frederick F. Kautz IV 05665a9111 Merge pull request #132 from fkautz/pr_out_removing_xml_header_from_response_in_docs 2015-02-04 16:40:22 -08:00
Frederick F. Kautz IV d44e42f809 Removing xml header from response in docs 2015-02-04 16:40:02 -08:00
Frederick F. Kautz IV e5cd3dcb7c Merge pull request #131 from fkautz/pr_out_removing_xmlname_from_json_request 2015-02-04 14:22:05 -08:00
Frederick F. Kautz IV 816310825e Removing XMLName from json request 2015-02-04 14:21:47 -08:00
Frederick F. Kautz IV ba4f8b3f56 Merge pull request #130 from fkautz/pr_out_adding_json_example_for_get_ 2015-02-04 14:04:54 -08:00
Frederick F. Kautz IV f1bf2cb5d7 Adding JSON Example for GET / 2015-02-04 14:04:41 -08:00
Frederick F. Kautz IV 2a6128a0b8 Merge pull request #129 from fkautz/pr_out_adding_additional_entry_into_bucket_list_in_docs 2015-02-03 17:36:23 -08:00
Frederick F. Kautz IV eded653fd2 Adding additional entry into bucket list in docs 2015-02-03 17:36:14 -08:00
Frederick F. Kautz IV 833dde6106 Merge pull request #128 from fkautz/pr_out_fixing_symlink_test_to_not_link_if_file_exists 2015-02-03 17:16:16 -08:00
Frederick F. Kautz IV 0646e7ae40 Fixing symlink test to not link if file exists 2015-02-03 17:15:57 -08:00
Frederick F. Kautz IV e4074f1580 Merge pull request #127 from fkautz/pr_out_accessing_dir_as_object_should_return_objectnotfound 2015-02-03 16:46:55 -08:00
Frederick F. Kautz IV 7152712f34 Accessing dir as object should return ObjectNotFound 2015-02-03 16:45:00 -08:00
Harshavardhana 297552e302 Merge pull request #126 from harshavardhana/pr_out_add_mkdocs_as_build_dependency_in_checkdeps_sh_and_builddeps_md 2015-02-03 00:42:28 -08:00
Harshavardhana b5d92aaa14 Add mkdocs as build dependency in checkdeps.sh and BUILDDEPS.md 2015-02-03 00:42:16 -08:00
Harshavardhana 3b0869e984 Merge pull request #125 from harshavardhana/pr_out_make_sure_config_testing_is_done_in_tempdir 2015-02-03 00:25:47 -08:00
Harshavardhana 582ce3df36 Make sure config testing is done in tempdir 2015-02-03 00:25:33 -08:00
Harshavardhana f4cd0aa978 Merge pull request #124 from harshavardhana/pr_out_add_json_config_reader_writer 2015-02-03 00:13:18 -08:00
Harshavardhana b1db70c807 Add json config reader/writer 2015-02-03 00:12:46 -08:00
Harshavardhana c26b6f3d76 Merge pull request #123 from harshavardhana/pr_out_use_helper_homedir_ 2015-02-02 21:45:37 -08:00
Harshavardhana aff4c5826b Use helper HomeDir() 2015-02-02 21:44:17 -08:00
Frederick F. Kautz IV 189e1b5302 Merge pull request #122 from fkautz/pr_out_minor_header_update_renaming_to_get_ 2015-02-02 16:23:34 -08:00
Frederick F. Kautz IV 60551dffca Minor header update, renaming '/' to 'GET /' 2015-02-02 16:23:18 -08:00
Frederick F. Kautz IV 5b5c798dee Merge pull request #121 from fkautz/pr_out_adding_mkdocs_to_gogenerate 2015-02-02 16:15:24 -08:00
Frederick F. Kautz IV a79a5c10e0 Adding mkdocs to gogenerate. 2015-02-02 16:14:55 -08:00
Frederick F. Kautz IV 41688e491c Merge pull request #120 from fkautz/pr_out_adding_minio_api_documentation 2015-02-02 15:42:07 -08:00
Frederick F. Kautz IV 9d4e7a50fc Adding minio api documentation 2015-02-02 15:41:21 -08:00
Frederick F. Kautz IV 246793e30e Merge pull request #119 from fkautz/pr_out_initial_mkdocs_configuration 2015-02-02 13:50:34 -08:00
Frederick F. Kautz IV ba1b7f79ba Initial mkdocs configuration 2015-02-02 13:50:07 -08:00
Frederick F. Kautz IV 42f5b3dc1d Removing docs 2015-02-02 13:50:07 -08:00
Harshavardhana 8bedf43a27 Merge pull request #118 from harshavardhana/pr_out_consolidate_developers_docs_and_makefile_create_symlink_automatically 2015-02-01 21:19:07 -08:00
Harshavardhana 88af9ba666 Consolidate developers docs and Makefile, create symlink automatically 2015-02-01 21:18:46 -08:00
Harshavardhana dd5380fc86 Merge pull request #117 from harshavardhana/pr_out_fix_build_issue 2015-02-01 17:21:55 -08:00
Harshavardhana dc47ca1431 Fix build issue 2015-02-01 17:21:17 -08:00
Frederick F. Kautz IV 4d5e4cd46f Merge pull request #116 from fkautz/pr_out_minioapi_testputobject_properly_creates_bucket_at_start_of_test 2015-02-01 14:46:59 -08:00
Frederick F. Kautz IV a8eef13835 Minioapi TestPutObject properly creates bucket at start of test 2015-02-01 14:46:45 -08:00
Frederick F. Kautz IV afd574af20 Merge pull request #115 from fkautz/pr_out_adding_test_to_ensure_list_objects_returns_an_error_for_non_existant_buckets_to_match_previous_bug_fix_and_fix_for_inmemory 2015-02-01 10:48:46 -08:00
Frederick F. Kautz IV a092b44cf1 Adding test to ensure list objects returns an error for non existant buckets to match previous bug fix and fix for inmemory 2015-02-01 10:48:31 -08:00
Harshavardhana be7c9aacf8 Merge pull request #114 from harshavardhana/pr_out_reply_back_errors_properly 2015-02-01 03:11:39 -08:00
Harshavardhana 5d197dd063 Reply back errors properly 2015-02-01 03:10:28 -08:00
Harshavardhana 862ce975d5 Merge pull request #113 from harshavardhana/pr_out_add_strictslash_for_path_re_direction 2015-02-01 02:49:27 -08:00
Harshavardhana b635501fb7 Add StrictSlash for path re-direction 2015-02-01 02:49:09 -08:00
Harshavardhana 3ed884e495 Merge pull request #112 from harshavardhana/pr_out_service_a_new_webui_server_at_port_8081 2015-02-01 02:45:21 -08:00
Harshavardhana e1b3836c60 Service a new WebUI server at port 8081.
It is provided to avoid the router clutter on the Object API
end. This is just a first cut sample we are going to build on
top of this the new management console UI.

General interest comes from subsequently writing a small UI to
generate `AccessKey` and `SecretKey` to build authorization
layer.
2015-02-01 02:44:53 -08:00
Frederick F. Kautz IV 392ca7451f Merge pull request #111 from fkautz/pr_out_setting_order_when_retrieving_buckets 2015-02-01 00:17:21 -08:00
Frederick F. Kautz IV 54026dbc78 Setting order when retrieving buckets 2015-02-01 00:16:25 -08:00
Harshavardhana c3287b7ad0 Merge pull request #110 from harshavardhana/pr_out_add_bucket_resources_to_ignore_handler 2015-01-31 22:47:37 -08:00
Harshavardhana 26aac9a439 Add bucket resources to ignore handler 2015-01-31 22:45:52 -08:00
Frederick F. Kautz IV 39250b7c49 Merge pull request #109 from fkautz/pr_out_converting_unimplemented_methods_list_into_an_http_handler 2015-01-31 19:50:48 -08:00
Frederick F. Kautz IV 94e124470c Converting unimplemented methods list into an http handler 2015-01-31 19:50:32 -08:00
Harshavardhana 9e5b689dc5 Merge pull request #103 from harshavardhana/pr_out_add_database_query_function 2015-01-31 15:52:16 -08:00
Harshavardhana 46751f0b28 Add database query function, and some re-factoring 2015-01-31 15:51:18 -08:00
Frederick F. Kautz IV bc779fcdea Merge pull request #102 from fkautz/pr_out_adding_sublime_workspace_to_gitignore 2015-01-30 17:39:22 -08:00
Frederick F. Kautz IV 68205c8c6c Adding sublime workspace to gitignore 2015-01-30 17:39:08 -08:00
Frederick F. Kautz IV d3e3bfee97 Merge pull request #101 from fkautz/pr_out_adding_list_api_test 2015-01-30 17:37:46 -08:00
Frederick F. Kautz IV 0cd54031a7 Adding list api test 2015-01-30 17:36:53 -08:00
Harshavardhana 0903b7c46d Merge pull request #100 from harshavardhana/pr_out_force_clients_to_have_certs 2015-01-30 16:52:46 -08:00
Harshavardhana 8a4128d304 Force clients to have certs 2015-01-30 16:51:33 -08:00
Frederick F. Kautz IV fec80fb1b3 Merge pull request #99 from fkautz/pr_out_using_generic_make_test_and_make_build_disabled_signers_code_for_now_to_fix_build 2015-01-30 10:59:06 -08:00
Frederick F. Kautz IV 84c5df8441 Using generic make test ./... and make build ./..., disabled signers code for now to fix build. 2015-01-30 10:58:47 -08:00
Frederick F. Kautz IV c3c5497d24 Merge pull request #98 from fkautz/pr_out_certificate_and_key_must_both_be_specified_or_empty_together 2015-01-29 11:29:54 -08:00
Frederick F. Kautz IV 91384e73cf Certificate and key must both be specified or empty together 2015-01-29 11:29:42 -08:00
Frederick F. Kautz IV 58da5c0f87 Merge pull request #97 from fkautz/pr_out_adding_list_bucket_tests_and_fixing_inmemory_behavior 2015-01-29 11:23:50 -08:00
Frederick F. Kautz IV 7ca87e06aa Adding list bucket tests and fixing inmemory behavior. 2015-01-29 11:23:14 -08:00
Harshavardhana 1306543b76 Merge pull request #96 from harshavardhana/pr_out_remove_redundant_tls_flag 2015-01-29 01:18:12 -08:00
Harshavardhana 7dd5f0ab8d Remove redundant --tls flag 2015-01-29 01:18:00 -08:00
Harshavardhana e3378ee448 Merge pull request #95 from harshavardhana/pr_out_getstoragetype_should_return_valid_results 2015-01-29 01:09:11 -08:00
Harshavardhana 8391a6e17a getStorageType should return valid results 2015-01-29 01:08:54 -08:00
Harshavardhana 966707a7ed Merge pull request #94 from harshavardhana/pr_out_prefix_if_empty_skip_it_before_isvalidbucket 2015-01-29 01:07:49 -08:00
Harshavardhana 82baccb8bf Prefix if empty skip it before IsValidBucket 2015-01-29 01:07:37 -08:00
Frederick F. Kautz IV 93b47bc097 Merge pull request #93 from fkautz/pr_out_reducing_code_duplication_relating_to_content_type 2015-01-28 20:47:56 -08:00
Frederick F. Kautz IV c6d537e66e Reducing code duplication relating to content type 2015-01-28 20:47:23 -08:00
Frederick F. Kautz IV de154550a3 Merge pull request #92 from fkautz/pr_out_updating_godep 2015-01-28 20:27:07 -08:00
Frederick F. Kautz IV 96a5fc0ee7 Updating godep 2015-01-28 20:26:52 -08:00
Frederick F. Kautz IV 092b8749cf Merge pull request #91 from fkautz/pr_out_removing_unnecessary_comments 2015-01-28 19:54:35 -08:00
Frederick F. Kautz IV 3e8765bb27 Removing unnecessary comments 2015-01-28 19:54:08 -08:00
Frederick F. Kautz IV 391468c80e Merge pull request #90 from fkautz/pr_out_reverting_back_to_codegansta_cli 2015-01-28 19:52:42 -08:00
Frederick F. Kautz IV 7b0942980b Reverting back to codegansta/cli 2015-01-28 19:52:30 -08:00
Harshavardhana 57d764778d Merge pull request #88 from harshavardhana/pr_out_add_x509_tests_and_should_be_part_of_the_build 2015-01-28 17:13:10 -08:00
Harshavardhana ac99968796 Add x509 tests and should be part of the build 2015-01-28 17:12:59 -08:00
Frederick F. Kautz IV be56e1cdad Merge pull request #87 from fkautz/pr_out_reordering_minioapi_functions 2015-01-28 16:51:59 -08:00
Frederick F. Kautz IV b170f3f5fc Reordering minioapi functions 2015-01-28 16:51:44 -08:00
Frederick F. Kautz IV 452d46bfa6 Merge pull request #86 from fkautz/pr_out_adding_comments_to_explain_design_decisions_in_server_go 2015-01-28 16:33:28 -08:00
Frederick F. Kautz IV 66cc370e8b Adding comments to explain design decisions in server.go 2015-01-28 16:33:20 -08:00
Frederick F. Kautz IV 698f0b815f Merge pull request #85 from fkautz/pr_out_http_server_package_now_follows_convention 2015-01-28 16:30:02 -08:00
Frederick F. Kautz IV f15e2c4e74 HTTP Server package now follows convention 2015-01-28 16:29:47 -08:00
Harshavardhana 1fdd62165e Merge pull request #83 from harshavardhana/pr_out_authorization_validation_in_accordance_with_s3_signer_awsv2 2015-01-28 16:14:39 -08:00
Harshavardhana d78cd581c5 Authorization validation in accordance with S3 signer AWSv2 2015-01-28 16:14:08 -08:00
Frederick F. Kautz IV 0225c51238 Merge pull request #84 from fkautz/pr_out_adding_server_config_structure 2015-01-28 16:08:03 -08:00
Frederick F. Kautz IV e8399a6d05 Adding server config structure 2015-01-28 16:07:53 -08:00
Frederick F. Kautz IV e25c39e20f Merge pull request #82 from fkautz/pr_out_fixing_build_break 2015-01-28 15:28:11 -08:00
Frederick F. Kautz IV f3e31fe795 Fixing build break 2015-01-28 15:27:59 -08:00
Frederick F. Kautz IV 801d3bf95c Merge pull request #81 from fkautz/pr_out_migrating_from_codegangsta_cli_to_spf13_cobra 2015-01-28 15:12:31 -08:00
Frederick F. Kautz IV e007a2db66 Migrating from codegangsta/cli to spf13/cobra 2015-01-28 15:12:02 -08:00
Frederick F. Kautz IV 910aa176b4 Merge pull request #80 from fkautz/pr_out_fix_build 2015-01-28 14:00:41 -08:00
Frederick F. Kautz IV ca7b1a7fc6 Fix build 2015-01-28 14:00:08 -08:00
Harshavardhana faf6835871 Merge pull request #79 from harshavardhana/pr_out_add_a_new_pkg_crypto_keys_first_cut 2015-01-28 12:03:28 -08:00
Harshavardhana fbafc98edb Add a new pkg/crypto/keys, first cut
- provides three functions
     - GetRandomAlphaNumeric()
     - GetRandomAlphaNumericFull()
     - GetRandomBase64()
     - ValidAccessKey()
2015-01-28 12:02:13 -08:00
Harshavardhana cc54730eee Merge pull request #78 from harshavardhana/pr_out_add_list_buckets_for_fs 2015-01-27 18:44:05 -08:00
Harshavardhana 2ccecd3f32 Add list buckets for 'fs' 2015-01-27 18:43:55 -08:00
Harshavardhana 3781734903 Merge pull request #77 from harshavardhana/pr_out_add_tiedot_integration_package_first_cut_more_improvements_needed 2015-01-27 18:15:50 -08:00
Harshavardhana c63a6dba2f Add 'tiedot' integration package, first cut - more improvements needed 2015-01-27 18:15:23 -08:00
Frederick F. Kautz IV cbf83f2d38 Merge pull request #76 from fkautz/pr_out_creating_subdirectories_in_fs_now_works 2015-01-27 17:48:05 -08:00
Frederick F. Kautz IV 5daa408e2c Creating subdirectories in fs now works 2015-01-27 17:47:11 -08:00
Harshavardhana 25ad24997e Merge pull request #75 from harshavardhana/pr_out_remote_syso_files_in_make_clean 2015-01-27 13:13:39 -08:00
Harshavardhana 07a1ad8b2d Remote syso files in 'make clean' 2015-01-27 13:13:25 -08:00
Frederick F. Kautz IV e1e8bf8b26 Merge pull request #74 from fkautz/pr_out_adding_more_tests_including_ordering_of_objects_in_prefix 2015-01-27 13:12:55 -08:00
Frederick F. Kautz IV 044dc9af80 Adding more tests, including ordering of objects in prefix 2015-01-27 13:11:22 -08:00
Harshavardhana af52f88187 Merge pull request #73 from harshavardhana/pr_out_fix_asm_path_for_yasm_version_check 2015-01-27 12:59:32 -08:00
Harshavardhana 0c87af7c64 Fix asm path for yasm version check 2015-01-27 12:59:21 -08:00
Harshavardhana aa4bc2549e Merge pull request #72 from harshavardhana/pr_out_add_erasure_package_in_its_full_form_v1_0 2015-01-27 12:57:51 -08:00
Harshavardhana 2547163cb2 Add erasure package in its full form v1.0 2015-01-27 12:55:17 -08:00
Frederick F. Kautz IV 77784ca884 Merge pull request #71 from fkautz/pr_out_removing_log_from_fs_test_go 2015-01-27 12:02:27 -08:00
Frederick F. Kautz IV 74ef65daac Removing log from fs_test.go 2015-01-27 12:02:08 -08:00
Frederick F. Kautz IV 027d1b0f70 Merge pull request #70 from fkautz/pr_out_adding_fs_storage 2015-01-27 11:11:25 -08:00
Frederick F. Kautz IV 163a6c35db Adding fs storage 2015-01-27 11:09:55 -08:00
Frederick F. Kautz IV 3461e7e300 Merge pull request #65 from fkautz/pr_out_adding_storage_modifications_for_upcoming_fs_system 2015-01-26 15:46:16 -08:00
Frederick F. Kautz IV 49641e3410 Adding storage modifications for upcoming fs system 2015-01-26 15:45:10 -08:00
Harshavardhana 7005d979bd Merge pull request #68 from harshavardhana/pr_out_avoid_clang_optimization_keep_it_o0 2015-01-26 12:23:26 -08:00
Harshavardhana f3a27169fc Avoid 'clang' optimization, keep it -O0 2015-01-26 12:22:08 -08:00
Harshavardhana 156c35e60a Merge pull request #67 from harshavardhana/pr_out_consolidate_reply_headers_simplify_contenttype 2015-01-25 18:24:08 -08:00
Harshavardhana b6627b4d6a Consolidate reply headers, simplify contentType 2015-01-25 18:23:39 -08:00
Harshavardhana e073295fb9 Merge pull request #66 from harshavardhana/pr_out_cosmetic_change_minio_to_be_installed_with_makefile 2015-01-25 17:46:05 -08:00
Harshavardhana 4c0804c5bc Cosmetic change 'minio' to be installed with Makefile 2015-01-25 17:45:00 -08:00
Harshavardhana b5deb198d3 Merge pull request #64 from harshavardhana/pr_out_add_server_connection_into_http_header_for_all_api_replies 2015-01-25 17:41:55 -08:00
Harshavardhana dfc3367e25 Add Server, Connection into HTTP header for all API replies 2015-01-25 17:40:22 -08:00
Harshavardhana 9e6eedfbbc Merge pull request #63 from harshavardhana/pr_out_implement_tls_server 2015-01-25 17:23:21 -08:00
Harshavardhana 063832baaf Implement TLS server
$ ./minio --tls --cert <your_cert> --key <your_private_key>

This patchset also provides crypto/x509 - which is a wrapper package
to generate X509 certificates.

This is necessary to provide certificates later through management console
2015-01-25 17:20:00 -08:00
Frederick F. Kautz IV 18ffa44c52 Merge pull request #62 from fkautz/pr_out_adding_error_support_to_all_commands_in_storage_interface 2015-01-25 15:35:22 -08:00
Frederick F. Kautz IV 2368e7c936 Adding error support to all commands in storage interface 2015-01-25 15:35:08 -08:00
Frederick F. Kautz IV b181ca7395 Merge pull request #61 from fkautz/pr_out_adding_istruncated_to_minioapi 2015-01-25 13:33:19 -08:00
Frederick F. Kautz IV d37bbfec41 Adding IsTruncated to minioapi 2015-01-25 13:32:39 -08:00
Frederick F. Kautz IV aef9e60694 Merge pull request #60 from fkautz/pr_out_adding_more_api_suite_tests 2015-01-25 13:07:11 -08:00
Frederick F. Kautz IV 39208601dc Adding more api suite tests 2015-01-25 13:06:36 -08:00
Frederick F. Kautz IV 8faaa2d21f Merge pull request #59 from fkautz/pr_out_adding_paging_count_tests 2015-01-25 12:58:22 -08:00
Frederick F. Kautz IV 0da193e6d6 Adding paging count tests 2015-01-25 12:57:58 -08:00
Frederick F. Kautz IV ef9968160e Merge pull request #58 from fkautz/pr_out_adding_initial_test_suites 2015-01-25 11:22:56 -08:00
Frederick F. Kautz IV 82a69d3ab9 Adding initial test suites 2015-01-25 11:22:38 -08:00
Harshavardhana 4b586a51cf Merge pull request #57 from harshavardhana/pr_out_for_listobjects_ignore_resources_should_be_for_buckets 2015-01-24 18:48:11 -08:00
Harshavardhana 15e832de64 For listobjects ignore resources should be for buckets 2015-01-24 18:46:23 -08:00
Harshavardhana 44f43809d7 Merge pull request #56 from harshavardhana/pr_out_return_http_statusnotimplemented_for_range_of_bucket_and_object_resources 2015-01-24 16:39:06 -08:00
Harshavardhana c751811dcb Return http.StatusNotImplemented for range of Bucket and Object resources
Not Implemented bucket resources
================================
    "acl":            true
    "lifecycle":      true
    "policy":         true
    "location":       true
    "logging":        true
    "notification":   true
    "versions":       true
    "requestPayment": true
    "versioning":     true
    "website":        true
    "uploads":        true

Not Implemented object resources
================================
    "uploadId":       true
    "acl":            true
    "torrent":        true
    "uploads":        true
2015-01-24 16:37:25 -08:00
Harshavardhana be9690f3e9 Merge pull request #55 from harshavardhana/pr_out_putbucket_before_putobject_in_testputobject 2015-01-24 15:43:17 -08:00
Harshavardhana 704d6d8b0a Putbucket before PutObject in TestPutObject 2015-01-24 15:42:24 -08:00
Harshavardhana 77210fead3 Merge pull request #54 from harshavardhana/pr_out_add_bucket_to_be_part_of_object_struct_reply_back_with_bucketnotfound_for_erroneous_object_put_requests 2015-01-24 15:38:56 -08:00
Harshavardhana 357a81e879 Add bucket to be part of object struct, reply back with BucketNotFound
for erroneous Object Put requests.

Other minor cleanups, to follow

  - https://github.com/golang/go/wiki/CodeReviewComments
2015-01-24 15:35:05 -08:00
Frederick F. Kautz IV b92acf386f Merge pull request #53 from fkautz/pr_out_adding_more_tests 2015-01-24 13:14:26 -08:00
Frederick F. Kautz IV af1ec94925 Adding more tests 2015-01-24 13:13:03 -08:00
Harshavardhana 72179fbc84 Merge pull request #52 from harshavardhana/pr_out_implement_crc32c_for_darwin_update_documentation 2015-01-23 19:44:16 -08:00
Harshavardhana 01d15ca3b2 Implement crc32c for Darwin, update documentation 2015-01-23 19:43:51 -08:00
Frederick F. Kautz IV 727a8669fa Merge pull request #51 from fkautz/pr_out_adding_tests_for_get_object_in_minioapi 2015-01-23 19:34:51 -08:00
Frederick F. Kautz IV dd0c833718 Adding tests for GET object in minioapi. 2015-01-23 19:33:56 -08:00
Harshavardhana 4c07aef9e5 Merge pull request #50 from harshavardhana/pr_out_add_osx_builddeps_installation_instructions_macosx_support_works_under_gcc_as_clang_lacks_some_extended_syntax_gas_support_issue_48 2015-01-23 17:31:26 -08:00
Frederick F. Kautz IV caa80f201e Merge pull request #49 from fkautz/pr_out_cleaning_up_more_code 2015-01-23 17:29:47 -08:00
Harshavardhana e890199cac Add OSX builddeps installation instructions, MacOSX support
works under ``GCC`` as ``Clang`` lacks some extended syntax
GAS support issue#48
2015-01-23 17:29:29 -08:00
Frederick F. Kautz IV 71833b4513 Cleaning up more code. 2015-01-23 17:29:27 -08:00
Frederick F. Kautz IV a3c0440b4a Merge pull request #47 from fkautz/pr_out_removing_date_format_method 2015-01-23 17:21:24 -08:00
Frederick F. Kautz IV 9224095420 Removing date format method 2015-01-23 17:19:38 -08:00
Harshavardhana ef3022a6c9 Merge pull request #46 from harshavardhana/pr_out_fix_content_type_in_getobjects 2015-01-23 13:16:48 -08:00
Harshavardhana c516c74c51 Fix content-type in GetObjects 2015-01-23 13:16:31 -08:00
Frederick F. Kautz IV aa2a714d50 Merge pull request #45 from fkautz/pr_out_cleaning_up_minioapi_code 2015-01-23 12:27:09 -08:00
Frederick F. Kautz IV 574742ec14 Cleaning up minioapi code 2015-01-23 12:26:37 -08:00
Harshavardhana 32abe927d0 Merge pull request #44 from harshavardhana/pr_out_get_bucket_list_objects_compliance_maxkeys_to_1000_rename_content_struct_to_item_for_cosmetic_reasons_for_xml_decoding_on_client_side 2015-01-23 12:16:37 -08:00
Harshavardhana d9d80f7c22 Get Bucket List objects compliance MaxKeys to 1000, Rename
Content struct to Item for cosmetic reasons for xml decoding
on client side
2015-01-23 12:15:01 -08:00
Harshavardhana 3e11e9a879 Merge pull request #43 from harshavardhana/pr_out_list_buckets_response_should_be_nested_xml_buckets 2015-01-23 01:57:44 -08:00
Harshavardhana 132e661136 List buckets response should be nested xml buckets
Additionally check for 'Header' content-type before
referencing it, as it may be empty value
2015-01-23 01:57:26 -08:00
Harshavardhana d482c39341 Merge pull request #42 from harshavardhana/pr_out_make_gcc_mandatory_on_osx_since_clang_lacks_certain_gas_features 2015-01-22 18:33:49 -08:00
Harshavardhana 3d43305b1f Make gcc mandatory on OSX, since clang lacks certain GAS features 2015-01-22 18:33:35 -08:00
Frederick F. Kautz IV 0de3dea797 Merge pull request #41 from fkautz/pr_out_cosmetic_change_sorting_routes 2015-01-22 16:20:11 -08:00
Frederick F. Kautz IV 8636e189e6 Cosmetic change, sorting routes 2015-01-22 16:19:55 -08:00
Frederick F. Kautz IV 7a5e95f12d Merge pull request #40 from fkautz/pr_out_adding_head_verb_to_minioapi 2015-01-22 14:26:09 -08:00
Frederick F. Kautz IV 8d1c447aac Adding HEAD verb to minioapi 2015-01-22 14:25:53 -08:00
Frederick F. Kautz IV 3a3d9989d1 Merge pull request #39 from fkautz/pr_out_making_in_memory_storage_data_type_private 2015-01-21 17:15:29 -08:00
Frederick F. Kautz IV 079cdcd909 Making in memory storage data type private 2015-01-21 17:15:05 -08:00
Frederick F. Kautz IV 3f6ddada56 Merge pull request #38 from fkautz/pr_out_migrating_from_unix_ts_to_time_time 2015-01-21 17:13:03 -08:00
Frederick F. Kautz IV 8efd23b755 Migrating from unix ts to time.Time 2015-01-21 17:12:47 -08:00
Frederick F. Kautz IV db32cb3e75 Merge pull request #37 from fkautz/pr_out_simplifying_bucket_name_convention_and_making_convention_public 2015-01-21 15:30:40 -08:00
Frederick F. Kautz IV 53a8536984 Fixing regex 2015-01-21 15:29:31 -08:00
Frederick F. Kautz IV 856781b2a4 Simplifying bucket name convention and making convention public 2015-01-21 15:22:15 -08:00
Frederick F. Kautz IV ae0b88f319 Simplfying bucket naming convention 2015-01-21 15:20:35 -08:00
Harshavardhana 06d06b8251 Merge pull request #36 from harshavardhana/pr_out_remove_http_unused_package 2015-01-21 15:15:07 -08:00
Harshavardhana 546e762abf Remove http unused package 2015-01-21 15:14:49 -08:00
Harshavardhana bd1df87bd3 Merge pull request #34 from fkautz/pr_out_adding_etag_to_headers 2015-01-21 15:07:16 -08:00
Harshavardhana 832319d06b Merge pull request #35 from harshavardhana/pr_out_add_arch_osx_for_isal_to_compile_properly_on_macosx 2015-01-21 15:05:34 -08:00
Harshavardhana 8582391ef6 Add arch=osx for isal to compile properly on MacOSX 2015-01-21 15:04:54 -08:00
Frederick F. Kautz IV 9ca1e37235 Adding etag to headers 2015-01-21 15:02:08 -08:00
Harshavardhana 3ecb0e82a1 Merge pull request #33 from harshavardhana/pr_out_add_arch_flags 2015-01-21 13:52:53 -08:00
Harshavardhana e7c74fdde2 Add ARCH flags 2015-01-21 13:52:42 -08:00
Harshavardhana 5cb49175b1 Merge pull request #32 from harshavardhana/pr_out_remove_linux_specific_code_for_now_bring_them_in_later 2015-01-21 13:48:04 -08:00
Harshavardhana 9401262f75 Remove linux specific code for now, bring them in later 2015-01-21 13:47:50 -08:00
Frederick F. Kautz IV e410337d26 Merge pull request #31 from fkautz/pr_out_extracting_storage_api_to_interface 2015-01-21 12:58:49 -08:00
Frederick F. Kautz IV c23fa26830 Extracting storage api to interface 2015-01-21 12:58:33 -08:00
Harshavardhana 63d9689214 Merge pull request #30 from harshavardhana/pr_out_provide_etag_with_sha256sum_of_input_object_data 2015-01-21 10:57:22 -08:00
Harshavardhana d44404dd81 Provide ETag with sha256Sum of input object data 2015-01-21 10:55:33 -08:00
Harshavardhana 5b67da7d96 Add PutBucket and ListBuckets service 2015-01-21 00:52:59 -08:00
Harshavardhana e22ae2475a Add license headers and other cleanup 2015-01-20 23:16:24 -08:00
Harshavardhana 9949a02e3e Merge pull request #2 from harshavardhana/pr_out_provide_package_http_as_a_http_server_wrapper
Provide package http as a http.Server wrapper
2015-01-20 23:15:16 -08:00
Frederick F. Kautz IV 761249934b Merge pull request #27 from fkautz/pr_out_adding_error_when_object_exists 2015-01-20 19:16:51 -08:00
Frederick F. Kautz IV 9a4c8bfaac Merge pull request #26 from fkautz/pr_out_adding_handler_for_listing_objects_to_both_trailing_and_non_trailing_url 2015-01-20 19:16:50 -08:00
Frederick F. Kautz IV 9260e6404a Adding error when object exists 2015-01-20 19:13:57 -08:00
Frederick F. Kautz IV 3026f77cfc Adding handler for listing objects to both trailing and non-trailing url 2015-01-20 19:10:52 -08:00
Frederick F. Kautz IV a7029206ff Merge pull request #25 from fkautz/pr_out_list_objects_in_a_bucket 2015-01-20 18:40:46 -08:00
Frederick F. Kautz IV cc4329fb12 List objects in a bucket. 2015-01-20 18:40:22 -08:00
Frederick F. Kautz IV d6fd1b0a38 Merge pull request #24 from fkautz/pr_out_initial_work_for_xml_list_objects 2015-01-20 16:08:46 -08:00
Frederick F. Kautz IV 53190e1210 Initial work for xml list objects 2015-01-20 16:08:14 -08:00
Frederick F. Kautz IV 5a4f472638 Merge pull request #23 from fkautz/pr_out_simplifying_code 2015-01-20 14:07:53 -08:00
Frederick F. Kautz IV 3c1580fcd9 Simplifying code 2015-01-20 14:07:39 -08:00
Harshavardhana b921c5b459 Merge pull request #22 from fkautz/pr_out_moving_scsi_pkg_away_from_errors_new
Moving scsi pkg away from errors.New
2015-01-20 11:35:43 -08:00
Frederick F. Kautz IV 2fedef04ac Moving scsi pkg away from errors.New 2015-01-20 11:34:05 -08:00
Frederick F. Kautz IV 50703cf4d6 Merge pull request #21 from fkautz/pr_out_adding_error_handling_to_storage_get_call 2015-01-19 17:39:35 -08:00
Frederick F. Kautz IV 36268f07ea Adding error handling to storage get call 2015-01-19 17:39:20 -08:00
Frederick F. Kautz IV cc288a5fd7 Merge pull request #20 from fkautz/pr_out_moving_web_logic_to_minioapi_package 2015-01-19 16:04:35 -08:00
Frederick F. Kautz IV f3705c5d61 Moving web logic to minioapi package 2015-01-19 15:59:01 -08:00
Frederick F. Kautz IV 7b91f2405c Merge pull request #19 from fkautz/pr_out_store_objects_in_memory_map 2015-01-19 10:33:50 -08:00
Frederick F. Kautz IV c791c7bca4 Store objects in memory map 2015-01-19 10:30:40 -08:00
Frederick F. Kautz IV 718794205f wip 2015-01-18 17:05:50 -08:00
Frederick F. Kautz IV 7db1d5afef Merge pull request #18 from fkautz/pr_out_closing_channel_when_http_server_dies 2015-01-18 17:05:44 -08:00
Frederick F. Kautz IV 2ede0bff52 Closing channel when http server dies
Fixing deadlock on error
2015-01-18 17:04:09 -08:00
Harshavardhana 3f03ce7334 Merge pull request #14 from fkautz/pr_out_handler_now_only_listens_to_get_requests
handler now only listens to GET requests
2015-01-18 16:57:26 -08:00
Frederick F. Kautz IV 1176d38e84 handler now only listens to GET requests 2015-01-18 16:23:17 -08:00
Frederick F. Kautz IV e1cd8d7412 Merge pull request #13 from fkautz/pr_out_populating_http_handler_with_test_scaffolding 2015-01-18 16:20:10 -08:00
Frederick F. Kautz IV c766f3617b Populating http handler with test scaffolding 2015-01-18 16:16:02 -08:00
Frederick F. Kautz IV 8d20e81295 Merge pull request #12 from fkautz/pr_out_minor_refactoring_moving_http_request_logic_from_storage_to_server 2015-01-18 15:51:04 -08:00
Frederick F. Kautz IV d3d1c1afb3 Minor refactoring, moving http request logic from storage to server 2015-01-18 15:50:53 -08:00
Harshavardhana 4e644a1f41 Merge pull request #11 from fkautz/pr_out_adding_initial_web_server_and_storage_server_module_infrastructure 2015-01-18 15:33:46 -08:00
Frederick F. Kautz IV f356599e22 Adding initial web server and storage server module infrastructure 2015-01-18 15:06:24 -08:00
Harshavardhana 34b3cb7f9f Merge pull request #9 from harshavardhana/pr_out_change_developer_md_to_contributing_md_in_accordance_with 2015-01-18 14:58:43 -08:00
Harshavardhana 511d415fc5 Change DEVELOPER.md to CONTRIBUTING.md in accordance with
-  https://github.com/blog/1184-contributing-guidelines
2015-01-18 14:57:28 -08:00
Frederick F. Kautz IV 530e609618 Merge pull request #10 from fkautz/pr_out_removing_old_server 2015-01-18 14:56:05 -08:00
Frederick F. Kautz IV f550e84cf4 Removing old server
Removing storage drivers
2015-01-18 14:54:46 -08:00
Harshavardhana 7c861eec12 Merge pull request #7 from fkautz/pr_out_removing_old_server
Removing old server
2015-01-17 20:25:02 -08:00
Frederick F. Kautz IV b8981ce946 Removing old server 2015-01-17 10:39:35 -08:00
Harshavardhana ad8010f2a4 Merge pull request #6 from harshavardhana/pr_out_consolidate_asm_s_from_crc32c_sha1_sha256_and_sha512 2015-01-15 23:11:08 -08:00
Harshavardhana b1266de212 Consolidate asm.S from crc32c, sha1, sha256 and sha512 2015-01-15 23:09:03 -08:00
Anand Babu (AB) Periasamy c8a65caf8c Merge pull request #5 from harshavardhana/pr_out_remove_assembly_code_bring_back_c_code
Remove assembly code bring back C code
2015-01-15 18:53:44 -08:00
Harshavardhana 3bf73642fd Remove assembly code bring back C code 2015-01-15 18:53:15 -08:00
Harshavardhana 6e84b1df97 Provide package http as a http.Server wrapper 2015-01-14 12:43:41 -08:00
Harshavardhana 0f66f0f5de Merge pull request #4 from harshavardhana/pr_out_further_restructure 2015-01-14 12:42:18 -08:00
Harshavardhana 68de9ac19e Further restructure 2015-01-14 12:40:43 -08:00
Harshavardhana 3178879b03 Merge pull request #3 from abperiasamy/make-clean 2015-01-14 12:21:24 -08:00
Anand Babu (AB) Periasamy d4d43fa018 clean isal files as well 2015-01-14 11:53:46 -08:00
Harshavardhana fb665c85d5 Merge pull request #1 from harshavardhana/pr_out_full_restructure_in_accordance_with 2015-01-14 11:34:53 -08:00
Harshavardhana 432275e966 Full restructure in accordance with
- pkg/{subsystem}/{package} style
  - modify Makefile to reflect the new style,
    consolidate various entries
  - add a dummy ``main.go`` at top level
2015-01-14 11:29:04 -08:00
Harshavardhana 033ad56a61 Merge pull request #167 from harshavardhana/pr_out_merge_with_intel_isal_changes_from_github_com_minio_io_isal 2015-01-11 00:43:46 -08:00
Harshavardhana f347a1e590 Merge with Intel ISAL changes from github.com/minio-io/isal
- These changes bring in a much needed Mac OSX port for
    Intel ISAL library
  - At the current stage this MacOSX part of code is
    considered beta
  - pkg/cpu now supports OSX
  - pkg/checksum/crc32c - is still WIP, rest of the packages
    have been validated
2015-01-11 00:39:39 -08:00
Harshavardhana 1dca91cd75 Update README.md 2015-01-08 19:10:42 -08:00
Harshavardhana 1c24353754 Update README.md 2015-01-08 19:05:21 -08:00
Harshavardhana c82d2b95d7 Merge pull request #166 from harshavardhana/pr_out_intel_isal_requires_yasm_version_1_2_0_with_avx2_instruction_support_document_it 2015-01-06 20:52:04 -08:00
Harshavardhana 35fa667164 Intel ISAL requires yasm version 1.2.0 > with AVX2 instruction support, document it! 2015-01-06 20:51:07 -08:00
Harshavardhana 43b1e178c2 Merge pull request #165 from harshavardhana/pr_out_disable_sha1_sha256_sha512_avx_avx2_sse3_crypto_implementations 2015-01-06 17:02:56 -08:00
Harshavardhana 462808b87a Disable sha1,sha256,sha512 avx,avx2,sse3 crypto implementations.
Re-implement them later, once stable
2015-01-06 17:02:25 -08:00
Harshavardhana d58f68ccaa Merge pull request #164 from harshavardhana/pr_out_add_checks_for_proper_yasm_installed_fixes_163 2015-01-06 15:30:33 -08:00
Harshavardhana c97ed4f0a4 Add checks for proper yasm installed - fixes #163 2015-01-06 15:30:02 -08:00
Harshavardhana ed7e58235d Merge pull request #162 from harshavardhana/pr_out_remove_stale_docs
Remove stale docs
2015-01-06 02:02:35 -08:00
Harshavardhana fcd768a88f Remove stale docs 2015-01-06 02:01:48 -08:00
Harshavardhana 9078743e6e Merge pull request #161 from harshavardhana/pr_out_add_supported_platforms_table
Add supported platforms table
2015-01-06 01:50:52 -08:00
Harshavardhana 9b016c900b Add supported platforms table 2015-01-06 01:49:42 -08:00
Harshavardhana 9e6a9657d1 Merge pull request #160 from fkautz/pr_out_adding_index_command
Adding index command
2015-01-06 01:31:58 -08:00
Frederick F. Kautz IV 992dea1bf3 Adding index command 2015-01-06 22:26:09 +13:00
Frederick F. Kautz IV d93e14e288 Merge pull request #159 from harshavardhana/pr_out_rename_split_file_split 2015-01-04 15:14:02 +13:00
Harshavardhana fff6b589cf Rename split-file --> split 2015-01-03 18:03:21 -08:00
Harshavardhana f02d6a2b2b Merge pull request #158 from fkautz/pr_out_adding_initial_split_file_command 2015-01-03 17:59:04 -08:00
Frederick F. Kautz IV f5010e1ee2 Adding initial split-file command 2015-01-04 14:47:37 +13:00
Frederick F. Kautz IV b5d84790a2 Further simplifying merging files. Eliminated a structure, switched to PipeWriter 2015-01-04 14:46:51 +13:00
Harshavardhana c3bc7176dc Merge pull request #157 from harshavardhana/pr_out_remove_template_files_make_them_const_strings_instead 2015-01-01 17:36:41 -08:00
Harshavardhana 0212079cd5 Remove template files, make them const strings instead 2015-01-01 17:31:51 -08:00
Harshavardhana 024b3a29d3 Update DEVELOPER.md 2014-12-30 17:45:17 -08:00
Harshavardhana 62d56f4a62 Update DEVELOPER.md 2014-12-30 17:42:09 -08:00
Harshavardhana 8088539c79 Update README.md 2014-12-30 17:34:37 -08:00
Harshavardhana c6d94292dd Update README.md 2014-12-30 04:33:47 -08:00
Harshavardhana fa401bf020 Update README.md 2014-12-30 04:27:45 -08:00
Harshavardhana 2ef22862d0 Add quora follow button 2014-12-30 04:22:24 -08:00
Harshavardhana 4915eee00f Merge pull request #156 from harshavardhana/pr_out_remove_freenode_moving_off_to_gitter 2014-12-30 03:14:12 -08:00
Harshavardhana 92636ef097 Remove freenode, moving off to gitter 2014-12-30 03:13:10 -08:00
Harshavardhana 8ee4d62ace Merge pull request #153 from harshavardhana/pr_out_fix_grammar 2014-12-30 02:44:46 -08:00
Harshavardhana c9dca1a395 Fix grammar 2014-12-30 02:44:08 -08:00
Harshavardhana 080b0d7c08 Merge pull request #152 from harshavardhana/pr_out_add_diskattrmap_scsiattrmap_for_probed_scsi_devices 2014-12-30 02:39:22 -08:00
Harshavardhana 0e4a26e3b4 Add Diskattrmap, Scsiattrmap for probed scsi devices
Additional changes

- Use ``iota`` for constants
- Remove unncessary C header files
- ``new-cmd`` now depends on codegangsta cli
2014-12-30 02:37:47 -08:00
Frederick F. Kautz IV 460fd63f05 Merge pull request #151 from harshavardhana/pr_out_a_full_restructure
A full restructure
2014-12-30 18:24:40 +13:00
Harshavardhana 6b36b5c551 A full restructure 2014-12-29 21:22:26 -08:00
Harshavardhana bdc4c3ebe7 Merge pull request #149 from harshavardhana/pr_out_implement_sysctl_map 2014-12-23 23:35:07 -08:00
Harshavardhana df6e89407e Implement sysctl map 2014-12-23 23:34:50 -08:00
Harshavardhana c65b971e97 Merge pull request #148 from harshavardhana/pr_out_mercurial_not_needed_anymore_export_goroot 2014-12-23 20:41:58 -08:00
Harshavardhana db49ad5c91 Mercurial not needed anymore, export GOROOT 2014-12-23 20:35:05 -08:00
Harshavardhana 6ad9e4e0d4 Merge pull request #147 from gitter-badger/gitter-badge
Add a Gitter chat badge to README.md
2014-12-22 16:39:16 -08:00
The Gitter Badger 3a7b6e3b8d Added Gitter badge 2014-12-23 00:38:08 +00:00
Harshavardhana d82066dcab Merge pull request #145 from harshavardhana/pr_out_implement_md5c_function_slower_than_golang_s_implementation_keeping_it_in_repo_to_make_further_improvements_and_also_rename 2014-12-21 03:52:00 -08:00
Harshavardhana 13650e088c Implement md5c function, slower than Golang's implementation
keeping it in repo to make further improvements and also rename

        minio-hash ---> crypto
2014-12-21 03:50:33 -08:00
Frederick F. Kautz IV 958890276d Merge pull request #144 from fkautz/pr_out_adding_minio_hash_to_install_via_makefile 2014-12-21 23:17:02 +13:00
Frederick F. Kautz IV 25c8bfee24 Adding minio-hash to install via Makefile 2014-12-21 23:16:29 +13:00
Frederick F. Kautz IV 5966f8b86b Merge pull request #142 from fkautz/pr_out_adding_minio_hash_with_streaming_crypto_hashes 2014-12-21 16:42:00 +13:00
Frederick F. Kautz IV ff55d40432 Adding md5, sha256, sha512 to Makefile 2014-12-21 13:40:09 +13:00
Frederick F. Kautz IV 2278df9910 Adding minio-hash with streaming crypto hashes 2014-12-21 13:04:41 +13:00
Harshavardhana aa6cd015fa Update README.md 2014-12-20 09:23:06 -08:00
Harshavardhana d7117b97e6 Merge pull request #141 from harshavardhana/pr_out_update_documentation 2014-12-20 09:09:48 -08:00
Harshavardhana d4c05f11c7 Update documentation 2014-12-20 09:09:35 -08:00
Harshavardhana d2784ba73d Merge pull request #140 from harshavardhana/pr_out_update_developer_docs_to_update_to_go1_4 2014-12-20 08:56:59 -08:00
Harshavardhana 2a54b9279a Update developer docs to update to Go1.4 2014-12-20 08:56:21 -08:00
Harshavardhana a3fc096aa7 Merge pull request #139 from fkautz/pr_out_switching_execpipe_output_to_io_reader
Switching execpipe output to io.Reader
2014-12-20 01:12:14 -08:00
Frederick F. Kautz IV 14dec50fef Switching execpipe output to io.Reader 2014-12-20 21:57:27 +13:00
Harshavardhana d1fe8beff5 Merge pull request #138 from harshavardhana/pr_out_add_simple_execpipe_to_be_used_with_filesystem_format_work
Add simple ExecPipe() to be used with filesystem format work
2014-12-19 03:33:25 -08:00
Harshavardhana 6e6f07c58b Add simple ExecPipe() to be used with filesystem format work 2014-12-19 03:32:13 -08:00
Harshavardhana ad998a16dd Merge pull request #137 from harshavardhana/pr_out_rename_appname_to_commandname_for_consistency 2014-12-19 00:18:34 -08:00
Harshavardhana b0e986c82c Rename appname to commandname for consistency 2014-12-19 00:16:41 -08:00
Harshavardhana a0b57edabe Merge pull request #136 from harshavardhana/pr_out_add_minio_cli_stub_generator 2014-12-19 00:01:08 -08:00
Harshavardhana 5268a62166 Add minio-cli stub generator 2014-12-19 00:00:14 -08:00
Harshavardhana 2b3be86727 Merge pull request #135 from fkautz/pr_out_command_list 2014-12-18 23:59:48 -08:00
Frederick F. Kautz IV ab97179323 Adding markdown manpages 2014-12-19 20:27:15 +13:00
Frederick F. Kautz IV e219c65c9d Command list 2014-12-19 09:27:58 +13:00
Harshavardhana 0a11b07f0c Merge pull request #134 from fkautz/pr_out_renaming_documents
Renaming documents
2014-12-17 14:49:39 -08:00
Frederick F. Kautz IV 338a8bcb4d Renaming documents 2014-12-18 09:36:04 +13:00
Harshavardhana 07cbb56221 Merge pull request #133 from harshavardhana/pr_out_add_pkgs_scsi_to_build 2014-12-17 03:36:30 -08:00
Harshavardhana e1b6f5391f Add pkgs/scsi to build 2014-12-17 03:36:10 -08:00
Harshavardhana c58d22977a Merge pull request #132 from harshavardhana/pr_out_add_linux_scsi_disk_detection_and_attribute_mapping 2014-12-17 03:31:43 -08:00
Harshavardhana e5953acf4b Add linux scsi disk detection and attribute mapping 2014-12-17 03:14:44 -08:00
Harshavardhana eaf08edc5e Merge pull request #131 from fkautz/pr_out_split_s_splitstream_now_creates_and_returns_a_read_only_channel
Split's SplitStream now creates and returns a read only channel.
2014-12-16 16:36:13 -08:00
Frederick F. Kautz IV c02fa65b0f Split's SplitStream now creates and returns a read only channel. 2014-12-17 12:34:53 +13:00
Frederick F. Kautz IV d73c57cff9 Split's JoinStream now creates and returns a read only channel 2014-12-17 12:32:57 +13:00
Harshavardhana fa52e8b355 Merge pull request #130 from harshavardhana/pr_out_implement_add_commit_instead_of_put_encoded 2014-12-15 21:56:29 -08:00
Harshavardhana 65e2031cfc Implement add, commit - instead of put, encoded 2014-12-15 21:55:54 -08:00
Harshavardhana 68eb14a1f6 Merge pull request #129 from harshavardhana/pr_out_move_wrappers_at_pkgs_minio_back_to_cmd_minio_as_their_usage_is_limited 2014-12-15 21:19:01 -08:00
Harshavardhana 98119707fb Move wrappers at pkgs/minio back to cmd/minio - as their usage is limited 2014-12-15 20:09:50 -08:00
Harshavardhana 1f8806b44f Merge pull request #128 from harshavardhana/pr_out_implement_commands 2014-12-15 19:13:32 -08:00
Harshavardhana 3ec5c2fb8f Implement commands
Commands implemented

   $ minio put <objectname> <file>
   $ minio encode <objectname>
   $ minio get <objectname>
   $ minio list

TODO :

   $ minio init
   $ minio verify
    ...
    ...
2014-12-15 14:59:15 -08:00
Frederick F. Kautz IV e3af681cc1 Merge pull request #127 from fkautz/pr_out_storage_objectstorage_list_is_now_list_objectpath_string 2014-12-15 19:32:09 +13:00
Frederick F. Kautz IV 5efc0d54f8 storage.ObjectStorage List() is now List(objectPath string) 2014-12-15 19:30:08 +13:00
Frederick F. Kautz IV 16e92521bd Merge pull request #126 from fkautz/pr_out_removing_fsstorage 2014-12-15 19:24:18 +13:00
Frederick F. Kautz IV 05baa6d9a2 Removing fsstorage 2014-12-15 19:15:22 +13:00
Harshavardhana 62797cd6a7 Merge pull request #125 from fkautz/pr_out_removing_unneeded_comment_from_storage_objectstorage
Removing unneeded comment from storage.ObjectStorage
2014-12-14 22:08:50 -08:00
Frederick F. Kautz IV d7e5e0df4f Removing unneeded comment from storage.ObjectStorage 2014-12-15 15:59:17 +13:00
Harshavardhana 9ea907e062 Merge pull request #124 from fkautz/pr_out_objectdescription_is_now_more_exact_only_exposes_necessary_details
ObjectDescription is now more exact, only exposes necessary details.
2014-12-14 17:37:01 -08:00
Frederick F. Kautz IV dd7cd11c9c ObjectDescription is now more exact, only exposes necessary details. 2014-12-15 14:26:16 +13:00
Harshavardhana 8ff7fea4ac Was ---> is 2014-12-14 15:03:39 -08:00
Harshavardhana baa74072b1 Merge pull request #123 from harshavardhana/pr_out_remove_stale_sha1_dir 2014-12-14 02:38:46 -08:00
Harshavardhana 2552ae450d Remove stale sha1 dir 2014-12-14 02:38:11 -08:00
Harshavardhana c46058282e Merge pull request #122 from harshavardhana/pr_out_update_docs
Update docs
2014-12-13 21:52:54 -08:00
Harshavardhana 363930e79d Update docs 2014-12-13 21:51:46 -08:00
Harshavardhana f6c37b41ca Merge pull request #121 from harshavardhana/pr_out_refactor_checksum_code_and_add_objectname_hashing_per_uploaded_objects 2014-12-13 21:44:31 -08:00
Harshavardhana 0148237e22 Refactor checksum code, and add Objectname hashing per uploaded objects
Add placeholder sha256, sha512 implementations from Intel with AVX, AVX2
and SSE4.1 extensions - with some boilerplate Go code.
2014-12-13 21:42:23 -08:00
Harshavardhana b87839a1c8 Merge pull request #120 from harshavardhana/pr_out_add_license_header 2014-12-13 14:27:59 -08:00
Harshavardhana 99478c524a Add license header 2014-12-13 14:27:06 -08:00
Harshavardhana 6c616f9bd0 Merge pull request #119 from harshavardhana/pr_out_update_documentation_for_crc32c_cpu 2014-12-13 01:39:31 -08:00
Harshavardhana 71c774f99b Update documentation for crc32c, cpu 2014-12-13 01:39:14 -08:00
Harshavardhana 643a293d94 Merge pull request #118 from harshavardhana/pr_out_provide_new_pkgs_utils_for_generic_functions 2014-12-13 01:15:02 -08:00
Harshavardhana 20d46a1977 Provide new pkgs/utils for generic functions 2014-12-13 01:14:36 -08:00
Harshavardhana fb1537248b Merge pull request #117 from harshavardhana/pr_out_how_to_join_community 2014-12-12 23:57:09 -08:00
Harshavardhana 41e9084770 How to Join Community 2014-12-12 23:52:25 -08:00
Harshavardhana 73063deaa6 Merge pull request #116 from harshavardhana/pr_out_fsstorage_should_use_appendstorage_with_offsets 2014-12-12 17:18:53 -08:00
Harshavardhana fc50291cac fsStorage should use appendStorage with offsets
- also takes in 'blockSize' cli option.
 - robustness fixes
2014-12-12 17:18:16 -08:00
Harshavardhana b570b486de Merge pull request #115 from harshavardhana/pr_out_add_list_object_support_for_erasure_and_append_storage_drivers 2014-12-12 02:56:13 -08:00
Harshavardhana 0a0e1111cd Add list() object support for erasure and append storage drivers
- Reply back objects with their protectionlevel and md5sum
  - // TODO hash value
  - Calculate md5sum after "storeBlocks()", to make sure data is committed
2014-12-12 02:52:37 -08:00
Harshavardhana 267aa87ad7 Merge pull request #114 from harshavardhana/pr_out_provide_new_cli_options_for_put_command
Provide new cli options for 'put' command
2014-12-11 22:57:56 -08:00
Harshavardhana f71b323e32 Provide new cli options for 'put' command
- --protection-level
  - --block-size
2014-12-11 22:56:12 -08:00
Harshavardhana 429836593b Merge pull request #113 from harshavardhana/pr_out_build_fixes_after_moving_to_go1_4 2014-12-11 20:59:13 -08:00
Harshavardhana 235949eafe Build fixes after moving to go1.4 2014-12-11 20:57:00 -08:00
Harshavardhana 0bd2b8516e Build fix, fixing without a PR 2014-12-11 20:44:06 -08:00
Harshavardhana 4a7d9a58f4 Merge pull request #112 from harshavardhana/pr_out_calculate_md5sum_for_each_object 2014-12-11 20:36:42 -08:00
Harshavardhana 91d1c938a8 Merge pull request #111 from harshavardhana/pr_out_implement_simple_encoded_storage_in_gateway 2014-12-11 20:36:31 -08:00
Harshavardhana e15edbf393 Implement simple encoded storage in gateway 2014-12-11 20:29:40 -08:00
Harshavardhana a0ec21975d Calculate md5sum for each object 2014-12-11 19:43:58 -08:00
Harshavardhana a56710e318 Merge pull request #110 from harshavardhana/pr_out_use_objectname_with_basename_for_the_filepath 2014-12-11 15:35:53 -08:00
Harshavardhana dddc555491 Use objectName with basename for the filepath 2014-12-11 15:35:25 -08:00
Harshavardhana 94e11db3a8 Merge pull request #109 from harshavardhana/pr_out_add_crc_checks_for_object_get_ 2014-12-11 15:10:51 -08:00
Harshavardhana 1166557da1 Add crc checks for Object Get() 2014-12-11 15:06:29 -08:00
Frederick F. Kautz IV b3af234ee2 Merge pull request #108 from fkautz/pr_out_updates_for_cli_and_context 2014-12-11 09:28:33 -08:00
Frederick F. Kautz IV c2290dd1d4 Updates for cli and context
cli adds new global options. We'll be able to specify flags that
apply to multiple options now.

context update fixes parallelWriter function, actually writes a value out now.
2014-12-11 09:19:20 -08:00
Harshavardhana e107c3204d Merge pull request #107 from harshavardhana/pr_out_storage_erasure_encoding_info_at_storageentry_and_also_store_crc_at_blockheader 2014-12-11 02:22:30 -08:00
Harshavardhana 803c35ee90 Storage erasure encoding info at StorageEntry and also store CRC at blockheader 2014-12-11 02:11:48 -08:00
Harshavardhana 23a3609a64 Merge pull request #106 from harshavardhana/pr_out_ignore_io_eof_for_gob_decoding 2014-12-11 01:47:49 -08:00
Harshavardhana c0724b38b9 Ignore io.EOF for gob decoding 2014-12-11 01:45:58 -08:00
Harshavardhana 063d668133 Merge pull request #105 from fkautz/pr_out_erasure_encoded_demo 2014-12-11 00:43:02 -08:00
Frederick F. Kautz IV 568ca4e1bc erasure encoded demo 2014-12-11 00:32:32 -08:00
Frederick F. Kautz IV e5995f0193 Merge pull request #104 from fkautz/pr_out_erasure_demo_put_now_takes_1_or_2_arguments 2014-12-11 00:20:45 -08:00
Harshavardhana d442988912 Merge pull request #103 from fkautz/pr_out_objectstorage_refactor_to_take_io_reader_instead_of_byte
ObjectStorage refactor to take io.Reader instead of []byte
2014-12-10 21:40:25 -08:00
Frederick F. Kautz IV a1040ae657 erasure-demo put now takes 1 or 2 arguments 2014-12-10 20:59:49 -08:00
Frederick F. Kautz IV 19da9760b3 ObjectStorage refactor to take io.Reader instead of []byte 2014-12-10 20:57:59 -08:00
Frederick F. Kautz IV c7b4e14f64 Merge pull request #102 from fkautz/pr_out_adding_list_path_to_object_storage_definition_and_accompanying_definition_to_fs 2014-12-10 19:19:26 -08:00
Frederick F. Kautz IV cae9b288b0 Adding List(path) to object storage definition and accompanying definition to fs 2014-12-10 19:15:03 -08:00
Harshavardhana 9142de1dd5 Merge pull request #101 from fkautz/pr_out_fixing_build
Fixing build
2014-12-10 19:00:34 -08:00
Frederick F. Kautz IV e670608226 Fixing build 2014-12-10 17:43:16 -08:00
Harshavardhana 9dd3dd8b53 Merge pull request #100 from harshavardhana/pr_out_add_crc32c_checksum_support_for_erasure_chunks
Add crc32c checksum support for erasure chunks
2014-12-10 11:53:23 -08:00
Harshavardhana 01c0e45b5c Add crc32c checksum support for erasure chunks
Now upon conditions

 - if checksum '.cksum' file is missing
 - or corrupted chunk (mismatching chunk)
 - or missing chunk entirely

Decoding works consistently
2014-12-10 00:58:15 -08:00
Harshavardhana 72ddb345a1 Merge pull request #99 from harshavardhana/pr_out_make_get_put_more_robust 2014-12-09 03:37:08 -08:00
Harshavardhana f6a5b61b00 Make get/put more robust
- init folder if not present already in 'get()' call
  - put.go was referencing wrong args - fix it
  - if no OBJECTNAME is specified during 'get' - grab a
    list of files under "~/.minio"
  - Provide new API GetList() for ObjectStorage struct
2014-12-09 03:32:31 -08:00
Harshavardhana 3fe2c2af01 Merge pull request #98 from harshavardhana/pr_out_add_sha1_avx2_supported_fast_implementation_with_some_crc32c_cleanup 2014-12-09 01:01:05 -08:00
Harshavardhana 43680cd7b6 Add sha1 - AVX2 supported fast implementation, with some crc32c cleanup 2014-12-09 01:00:02 -08:00
Frederick F. Kautz IV 93e57118f8 Merge pull request #97 from fkautz/pr_out_adding_append_storage_driver 2014-12-08 23:37:54 -08:00
Frederick F. Kautz IV 1d7b3866cb Adding append storage driver 2014-12-08 23:37:25 -08:00
Frederick F. Kautz IV 76f21c1cfc Merge pull request #96 from fkautz/pr_out_removing_printlns_from_test_code 2014-12-08 20:40:08 -08:00
Frederick F. Kautz IV af8eb7a55d Removing printlns from test code 2014-12-08 20:39:30 -08:00
Frederick F. Kautz IV a40d834a42 Merge pull request #95 from fkautz/pr_out_adding_extremely_simple_fs_based_get_and_put_in_erasure_demo 2014-12-08 20:23:02 -08:00
Frederick F. Kautz IV d1ebf935da Adding extremely simple fs based get and put in erasure-demo 2014-12-08 20:20:25 -08:00
Frederick F. Kautz IV c2917f0d64 Merge pull request #94 from fkautz/pr_out_refactoring_file_storage_driver_to_fsstorage 2014-12-08 15:27:37 -08:00
Frederick F. Kautz IV 0cf80e075e Refactoring file storage driver to fsstorage 2014-12-08 14:29:25 -08:00
Frederick F. Kautz IV 8a5b8ac90f Merge pull request #93 from fkautz/pr_out_cpu_tests_now_actually_test_properly_on_linux_and_return_bool_instead_of_int 2014-12-08 14:25:11 -08:00
Frederick F. Kautz IV e71998c584 CPU tests now actually test properly on linux and return bool instead of int 2014-12-08 13:10:18 -08:00
Harshavardhana 5d4c02ad4a Merge pull request #92 from harshavardhana/pr_out_fixes_71_some_crazy_races_inside_erasure_and_simplify_the_code 2014-12-07 01:34:23 -08:00
Harshavardhana 7314b5e37d Fixes #71 - some crazy races inside erasure and simplify the code
- This change also brings in changing 'unsigned char' to 'uint8_t'
for brevity
2014-12-07 01:33:49 -08:00
Harshavardhana d57700922d Merge pull request #91 from harshavardhana/pr_out_remove_cpufeatures_c_code_since_pkgs_crc32c_cpu_should_be_used_instead
Remove cpufeatures C code, since pkgs/crc32c/cpu should be used instead
2014-12-05 17:26:03 -08:00
Harshavardhana e414d5f67b Remove cpufeatures C code, since pkgs/crc32c/cpu should be used instead 2014-12-05 17:25:42 -08:00
Harshavardhana f68baeaab2 Merge pull request #90 from harshavardhana/pr_out_provide_joinfileswithprefix_case_with_gochannel
Provide JoinFilesWithPrefix case with Gochannel
2014-12-05 17:22:19 -08:00
Harshavardhana 9a5003dd25 Provide JoinFilesWithPrefix case with Gochannel 2014-12-05 16:02:46 -08:00
Harshavardhana d34d86c050 Merge pull request #87 from fkautz/pr_out_adding_more_unit_tests_to_strbyteconv_fixes_69
Adding more unit tests to strbyteconv. Fixes #69.
2014-12-04 23:11:08 -08:00
Frederick F. Kautz IV 5abcaf4d58 Adding more unit tests to strbyteconv. Fixes #69. 2014-12-04 23:03:21 -08:00
Harshavardhana 1b283441a4 Merge pull request #80 from harshavardhana/pr_out_add_git_and_mercurial_as_dependencies 2014-12-04 01:57:15 -08:00
Harshavardhana c3fca84f25 Add git and mercurial as dependencies 2014-12-04 01:56:08 -08:00
Harshavardhana 69ae3b3310 Merge pull request #79 from abperiasamy/pr_out_updated_developers_guide 2014-12-04 01:22:34 -08:00
Anand Babu (AB) Periasamy 0464e2f8cc updated developers guide 2014-12-04 01:18:26 -08:00
Harshavardhana 0a42a82df5 Merge pull request #78 from harshavardhana/pr_out_avoid_linux_to_be_hard_dependency_on_build 2014-12-04 01:13:28 -08:00
Harshavardhana 0c4dd8f5fa Avoid linux to be hard dependency on build 2014-12-04 01:12:10 -08:00
Harshavardhana a2e0a41f7e Merge pull request #76 from harshavardhana/pr_out_fast_crc_implementations_ported_from_intel_s_efforts 2014-12-03 01:35:54 -08:00
Harshavardhana fb34c5290c Fast CRC implementations ported from Intel's efforts
Provides fast CRC32C with PCLMULQDQ instructions in Golang

The white papers on CRC32C calculations with PCLMULQDQ instruction can be
  downloaded from:

http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/crc-iscsi-polynomial-crc32-instruction-paper.pdf
http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-paper.pdf
2014-12-03 01:20:31 -08:00
Harshavardhana d31050803b Merge pull request #77 from harshavardhana/pr_out_change_instructions_for_go_installation_to_directory_inside_users_home_dir
Change instructions for go installation to directory inside users ${HOME} dir
2014-12-02 13:15:34 -08:00
Harshavardhana 18234c0666 Change instructions for go installation to directory inside users ${HOME} dir 2014-12-02 13:14:55 -08:00
Harshavardhana 39beabbbb6 Merge pull request #74 from fkautz/pr_out_adding_chunking_by_block_to_erasure_demo_via_block_size_parameter
Adding chunking by block to erasure-demo via --block-size parameter
2014-12-01 21:45:17 -08:00
Frederick F. Kautz IV dac14cd7a1 Merge pull request #75 from harshavardhana/pr_out_remove_unnecessary_c_code_and_use_everything_from_golang 2014-12-01 21:10:21 -08:00
Harshavardhana 3a6cac8ada Remove unnecessary C code and use everything from Golang 2014-12-01 21:07:55 -08:00
Frederick F. Kautz IV 46b08681a4 Adding chunking by block to erasure-demo via --block-size parameter 2014-12-01 21:06:36 -08:00
Harshavardhana 59c1197f47 Merge pull request #73 from fkautz/pr_out_adding_file_splitter_and_streaming_byte_chunker
Adding file splitter and streaming byte chunker
2014-12-01 20:47:25 -08:00
Frederick F. Kautz IV 89587e1391 Adding file splitter and streaming byte chunker 2014-12-01 18:51:47 -08:00
Harshavardhana 3b010d4813 Merge pull request #72 from harshavardhana/pr_out_build_restructure_top_level
Build restructure top level
2014-12-01 14:46:34 -08:00
Harshavardhana 6e4583ef1d Build restructure top level 2014-12-01 14:45:50 -08:00
Harshavardhana c2b52590ee Merge pull request #70 from harshavardhana/pr_out_enable_cover_profile_and_test_for_split_and_strbyteconv
Enable cover profile and test for split and strbyteconv
2014-12-01 10:58:34 -08:00
Harshavardhana a4676211cf Enable cover profile and test for split and strbyteconv 2014-12-01 10:40:50 -08:00
Harshavardhana c002f90e0b Merge pull request #28 from harshavardhana/pr_out_enable_way_to_split_files_at_input_bytes
Enable way to split files at input bytes
2014-12-01 01:03:17 -08:00
Harshavardhana 3a18454f5e Merge pull request #67 from fkautz/pr_out_refactoring_input_parsing_for_erasure_demo
Refactoring input parsing for erasure-demo
2014-12-01 01:03:05 -08:00
Harshavardhana 67e9a27b34 Enable way to split files at input bytes 2014-12-01 01:00:56 -08:00
Harshavardhana 2bea464c32 Merge pull request #68 from harshavardhana/pr_out_strbyteconv_stringtobytes_bytestostring_
strbyteconv -    - StringToBytes()    - BytesToString()
2014-12-01 00:37:04 -08:00
Harshavardhana ad5b4b52e8 strbyteconv -
- StringToBytes()
   - BytesToString()
2014-11-30 23:06:47 -08:00
Frederick F. Kautz IV 323a7b8492 Refactoring input parsing for erasure-demo 2014-11-30 22:18:23 -08:00
Harshavardhana 2a2e67cb50 Merge pull request #66 from fkautz/pr_out_fixing_build_where_cover_and_godep_cause_a_break_when_system_is_offline
Fixing build where cover and godep cause a break when system is offline
2014-11-30 21:59:21 -08:00
Frederick F. Kautz IV d1f9704f25 Fixing build where cover and godep cause a break when system is offline 2014-11-30 21:58:39 -08:00
Harshavardhana a110792ba5 Merge pull request #65 from harshavardhana/pr_out_remove_redundant_make_getdeps
Remove redundant 'make getdeps'
2014-11-30 16:37:27 -08:00
Harshavardhana 099d81e5c9 Remove redundant 'make getdeps' 2014-11-30 16:37:01 -08:00
Harshavardhana 653ad20c67 Merge pull request #64 from harshavardhana/pr_out_cleanup_makefile
Cleanup makefile
2014-11-30 15:20:32 -08:00
Harshavardhana fa1a13a8bf Cleanup makefile 2014-11-30 15:20:20 -08:00
Harshavardhana 08c8a029be Merge pull request #63 from harshavardhana/pr_out_update_readme_with_clear_instructions
Update readme with clear instructions
2014-11-30 15:13:48 -08:00
Harshavardhana eaf5379246 Update readme with clear instructions 2014-11-30 15:09:58 -08:00
Frederick F. Kautz IV 51022972f8 Merge pull request #61 from fkautz/pr_out_renaming_minio_demo_to_erasure_demo 2014-11-30 13:54:59 -08:00
Frederick F. Kautz IV 6382ee161e Renaming minio-demo to erasure-demo 2014-11-30 13:54:31 -08:00
Harshavardhana db4ad37fee Merge pull request #62 from fkautz/pr_out_removing_groupcache_lru_dependency
Removing groupcache lru dependency
2014-11-30 13:50:00 -08:00
Frederick F. Kautz IV af273c5d0f Removing groupcache lru dependency 2014-11-30 13:49:06 -08:00
Harshavardhana fdf860e8eb Merge pull request #60 from fkautz/pr_out_adding_godoc_description_of_minio
Adding godoc description of minio
2014-11-30 13:12:41 -08:00
Frederick F. Kautz IV b98965604c Adding godoc description of minio 2014-11-30 13:11:37 -08:00
Harshavardhana 0c16744e2c Merge pull request #59 from harshavardhana/pr_out_no_caps_for_stdint
No caps for stdint
2014-11-30 12:37:34 -08:00
Harshavardhana 7e79721452 No caps for stdint 2014-11-30 11:57:58 -08:00
Harshavardhana 7d47b72f1d Merge pull request #58 from fkautz/pr_out_increasing_parity_from_5_to_6
Increasing parity from 5 to 6
2014-11-29 23:04:37 -08:00
Frederick F. Kautz IV 30687a8c66 Increasing parity from 5 to 6 2014-11-29 22:59:44 -08:00
Harshavardhana 07e1199ae1 Merge pull request #57 from fkautz/pr_out_merging_encode_and_decode_to_single_minio_demo_binary
Merging encode and decode to single minio-demo binary
2014-11-29 22:51:10 -08:00
Frederick F. Kautz IV 3c09029049 Merging encode and decode to single minio-demo binary 2014-11-29 22:48:37 -08:00
Harshavardhana a37bb693ba Merge pull request #56 from harshavardhana/pr_out_fix_function_name_change
Fix function name change
2014-11-29 17:30:33 -08:00
Harshavardhana 5074542636 Fix function name change 2014-11-29 17:29:38 -08:00
Harshavardhana 980ad3b373 Merge pull request #55 from harshavardhana/pr_out_decoding_bug_fixes_42
Decoding bug fixes #42
2014-11-29 17:24:40 -08:00
Harshavardhana 4d7c1e3b68 Decoding bug fixes #42 2014-11-29 17:22:31 -08:00
Harshavardhana a6e75f42dd Merge pull request #53 from fkautz/pr_out_moving_gateway_and_storage_driver_to_packages
Moving gateway and storage driver to packages
2014-11-29 16:33:07 -08:00
Harshavardhana 5e0c5089e6 Merge pull request #49 from fkautz/pr_out_adding_initial_documentation_to_erasure_package
Adding initial documentation to erasure package
2014-11-29 14:59:35 -08:00
Frederick F. Kautz IV 96e42a8443 Adding initial documentation to erasure package 2014-11-29 14:59:09 -08:00
Harshavardhana 48898d770d Merge pull request #54 from fkautz/pr_out_exposing_newencoder_since_getencoder_is_no_longer_around
Exposing NewEncoder since GetEncoder is no longer around
2014-11-29 14:57:42 -08:00
Frederick F. Kautz IV 3da8e53ab8 Exposing NewEncoder since GetEncoder is no longer around 2014-11-29 14:54:21 -08:00
Frederick F. Kautz IV 03beef3afc Moving gateway and storage driver to packages 2014-11-29 14:42:22 -08:00
Harshavardhana dc5d7434e1 Merge pull request #52 from harshavardhana/pr_out_rename_newencoder_newencoder
Rename NewEncoder-->newEncoder
2014-11-29 14:42:03 -08:00
Harshavardhana 17a23876a2 Rename NewEncoder-->newEncoder 2014-11-29 14:41:20 -08:00
Harshavardhana a86de74983 Merge pull request #50 from fkautz/pr_out_removing_lru_from_erasure_package
Removing LRU from erasure package
2014-11-29 14:39:07 -08:00
Harshavardhana c2b8fee677 Merge pull request #47 from harshavardhana/pr_out_erasure_restructuring
Erasure restructuring
2014-11-29 14:30:01 -08:00
Harshavardhana 922e6bac0b Erasure restructuring 2014-11-29 14:28:55 -08:00
Frederick F. Kautz IV 9ef1ef5c8c Removing LRU from erasure package 2014-11-29 13:45:44 -08:00
Harshavardhana d6b65f1f04 Merge pull request #46 from harshavardhana/pr_out_make_sure_to_use_simd_alignment_with_32 2014-11-27 02:59:55 -08:00
Harshavardhana 618e0e1b04 Update README.md 2014-11-27 02:49:20 -08:00
Harshavardhana 3a3d3c8d1e Update README.md 2014-11-27 02:45:42 -08:00
Harshavardhana f1fcd3be06 Make sure to use SIMD Alignment with 32 2014-11-27 02:15:41 -08:00
Frederick F. Kautz IV fd52a211f4 Merge pull request #45 from fkautz/pr_out_simplifying_code 2014-11-26 23:33:57 -08:00
Frederick F. Kautz IV becb165770 Simplifying code 2014-11-26 23:33:36 -08:00
Harshavardhana 12aae70620 Merge pull request #44 from harshavardhana/pr_out_restructure_directory_add_pkgs_folder_now
Restructure directory, add 'pkgs' folder now
2014-11-24 15:11:48 -08:00
Harshavardhana 3cefaf5ad8 Restructure directory, add 'pkgs' folder now 2014-11-24 15:10:25 -08:00
Harshavardhana 1707b87ddd Merge pull request #43 from harshavardhana/pr_out_remove_overview_diagram_for_now 2014-11-24 13:11:24 -08:00
Harshavardhana 0e9764fd83 Remove overview diagram for now 2014-11-24 13:09:52 -08:00
Harshavardhana a1aafb9648 Merge pull request #41 from harshavardhana/pr_out_make_use_of_lru_and_higher_order_erasure_functions
Make use of LRU and higher order erasure functions
2014-11-24 08:14:58 -08:00
Harshavardhana 6592ef3bd2 Make use of LRU and higher order erasure functions 2014-11-24 07:16:54 -08:00
Harshavardhana 95e2e472cd Merge pull request #40 from harshavardhana/pr_out_decode_on_chunks_missing_should_build_and_continue 2014-11-24 07:03:00 -08:00
Harshavardhana ee7ff7c436 Decode on chunks missing should build and continue 2014-11-24 06:58:27 -08:00
Harshavardhana bd5a8c126c Merge pull request #39 from fkautz/pr_out_adding_minio_decode 2014-11-24 06:52:08 -08:00
Harshavardhana a98cf10920 Update README.md 2014-11-23 23:08:43 -08:00
Frederick F. Kautz IV 5a3eb47583 Adding minio-decode 2014-11-23 19:32:01 -08:00
Harshavardhana 4b97cf4b9d Merge pull request #38 from fkautz/pr_out_adding_k_and_m_as_optional_parameters_for_encoding_in_minio_encode
Adding k and m as optional parameters for encoding in minio-encode
2014-11-23 17:36:32 -08:00
Frederick F. Kautz IV cec0a0ef68 Adding k and m as optional parameters for encoding in minio-encode 2014-11-23 15:49:26 -08:00
Harshavardhana 2aa21866de Merge pull request #37 from harshavardhana/pr_out_only_build_static_lib
Only build static lib
2014-11-22 21:47:55 -08:00
Harshavardhana 63d63e51ed Only build static lib 2014-11-22 21:47:35 -08:00
Harshavardhana 5225a6b7f0 Merge pull request #36 from harshavardhana/pr_out_add_minio_overview
Add minio overview
2014-11-22 21:26:38 -08:00
Harshavardhana 29cc682fc0 Add minio overview 2014-11-22 21:25:07 -08:00
Harshavardhana 42ba0af9ac Merge pull request #35 from fkautz/pr_out_adding_input_and_output_file_parameters_to_minio_encode
Adding input and output file parameters to minio-encode.
2014-11-22 21:02:05 -08:00
Frederick F. Kautz IV 6faa55e25a Adding input and output file parameters to minio-encode. 2014-11-22 19:25:46 -08:00
Frederick F. Kautz IV eb36c9e4d1 Merge pull request #34 from harshavardhana/pr_out_vandermonde_cauchy 2014-11-22 18:52:44 -08:00
Harshavardhana 3b9495d91a Vandermonde --> Cauchy 2014-11-22 18:52:07 -08:00
Harshavardhana 6fa2ad2444 Merge pull request #31 from fkautz/pr_out_adding_minio_encode_binary
Adding minio-encode binary
2014-11-22 18:47:46 -08:00
Frederick F. Kautz IV a15e935a33 Adding minio-encode binary 2014-11-22 18:39:59 -08:00
Frederick F. Kautz IV 7ca422f972 Merge pull request #33 from fkautz/pr_out_adding_cover_out_to_gitignore 2014-11-22 18:32:32 -08:00
Frederick F. Kautz IV 2e8a68a796 Adding cover.out to gitignore 2014-11-22 18:31:49 -08:00
Frederick F. Kautz IV 4c16e6e9ef Merge pull request #32 from mattf/master 2014-11-22 18:30:46 -08:00
Matthew Farrellee 5047c055f6 stop requiring a cover directory
it is not automatically created. instead, store coverage output in the
current directory.
2014-11-22 21:13:56 -05:00
Matthew Farrellee fe0e13dd6b add missing deps 2014-11-22 21:11:40 -05:00
Harshavardhana be17f50d17 Merge pull request #30 from fkautz/pr_out_removing_binaries
Removing binaries
2014-11-22 17:06:12 -08:00
Frederick F. Kautz IV 9c18624e58 Removing binaries 2014-11-22 15:16:38 -08:00
Harshavardhana 324c23f12e Merge pull request #29 from fkautz/pr_out_fixing_isal_compile_from_root_workaround_for_https_code_google_com_p_go_issues_detail_id_7891
Fixing isal compile from root, workaround for https://code.google.com/p/go/issues/detail?id=7891
2014-11-22 13:14:35 -08:00
Frederick F. Kautz IV 1a6b9ccfc8 Fixing isal compile from root, workaround for https://code.google.com/p/go/issues/detail?id=7891 2014-11-22 13:09:05 -08:00
Frederick F. Kautz IV 084d029b54 Merge pull request #27 from harshavardhana/pr_out_use_deepequals_instead_of_bytes_compare
Use DeepEquals instead of bytes Compare
2014-11-17 01:07:45 -07:00
Harshavardhana 22853ed1d9 Use DeepEquals instead of bytes Compare 2014-11-17 00:06:42 -08:00
Harshavardhana d476a9d87e Merge pull request #26 from fkautz/pr_out_adding_simple_file_storage_driver_for_persistent_storage
Adding simple file storage driver for persistent storage
2014-11-15 04:43:27 -08:00
Harshavardhana a468afca03 Merge pull request #25 from fkautz/pr_out_moving_minio_command_to_cmd_minio
Moving minio command to cmd/minio
2014-11-15 04:43:17 -08:00
Frederick F. Kautz IV 44b28166f5 Adding simple file storage driver for persistent storage 2014-11-14 18:22:50 -07:00
Frederick F. Kautz IV f8f9f65652 Moving minio command to cmd/minio 2014-11-14 18:20:40 -07:00
Harshavardhana 2679324afe Merge pull request #24 from harshavardhana/pr_out_add_groupcache_lru_into_godep
Add groupcache/lru into godep
2014-11-13 22:46:25 -08:00
Harshavardhana 3ad5f2d955 Add groupcache/lru into godep 2014-11-13 22:41:44 -08:00
Frederick F. Kautz IV c4d2292a7d Merge pull request #18 from fkautz/pr_out_bucket_manager_is_now_configurable_as_gatewayconfig_bucketservicedriver 2014-11-13 22:23:08 -08:00
Frederick F. Kautz IV 101ce51f78 Bucket manager is now configurable as GatewayConfig.BucketServiceDriver 2014-11-13 22:20:35 -08:00
Harshavardhana f46fad48b0 Merge pull request #23 from harshavardhana/pr_out_squashed_contrib_signify_changes_from_a1554a4_35fe2d3
Squashed 'contrib/signify/' changes from a1554a4..35fe2d3
2014-11-13 21:55:39 -08:00
Harshavardhana 88ea40a2e8 Merge commit 'ef0a8b4d2e245be27cc27a782fb1b807ed0e2618' 2014-11-13 21:54:50 -08:00
Harshavardhana ef0a8b4d2e Squashed 'contrib/signify/' changes from a1554a4..35fe2d3
35fe2d3 Update upstream diff
2b7bf89 Generate shared libs

git-subtree-dir: contrib/signify
git-subtree-split: 35fe2d347b161b9ee18ca33c9d5a54bb466eecbf
2014-11-13 21:54:50 -08:00
Harshavardhana fa13804db0 Merge pull request #22 from harshavardhana/pr_out_erasure_coding_blocks_during_encoding_were_garbage_fixes_21
erasure: Coding blocks during encoding were garbage, fixes #21
2014-11-13 21:49:23 -08:00
Harshavardhana 6a6dac8365 erasure: Coding blocks during encoding were garbage, fixes #21 2014-11-13 21:48:04 -08:00
Harshavardhana c39c51328e Merge pull request #16 from fkautz/pr_out_moving_bucket_request_channel_to_private_config_option
Moving bucket request channel to private config option
2014-11-13 15:21:46 -08:00
Harshavardhana d88158b75a Merge pull request #15 from harshavardhana/go_isal_binding
Add erasure coding and decoding using Intel Storage Acceleration library
2014-11-13 15:21:36 -08:00
Harshavardhana 1e7515a7df Add erasure coding and decoding using Intel Storage Acceleration library
- move contrib/erasure --> contrib/isal
 - bring in low level 'isal' package for Go for exposing C functions
 - Implement Erasure 'encoding'
   Supports - Reed Solomon Codes, Cauchy Codes
 - Implement Erasure 'decoding'
   Supports - Reed Solomon Codes, Cauchy Codes
 - Renames Minios -> Minio at all the references
2014-11-13 15:20:18 -08:00
Anand Babu (AB) Periasamy cbce7fd66f Merge pull request #19 from fkautz/pr_out_in_memory_object_storage_now_uses_patricia_tree
In memory object storage now uses patricia tree
2014-11-08 00:11:49 -08:00
Frederick F. Kautz IV e0b9a59ad4 In memory object storage now uses patricia tree 2014-11-07 23:34:21 -08:00
Frederick F. Kautz IV 0ed2aeb439 Merge pull request #17 from fkautz/pr_out_changing_minios_to_minio 2014-11-07 22:29:02 -08:00
Frederick F. Kautz IV 9275afa173 Changing minios to minio 2014-11-07 22:23:52 -08:00
Frederick F. Kautz IV 4e6214514f Moving bucket request channel to private config option 2014-11-07 19:07:16 -08:00
Harshavardhana 00b5a5d380 Merge pull request #14 from fkautz/pr_out_cleaning_up_more_code_system_generated_by_config
Cleaning up more code, system generated by config
2014-11-06 23:23:26 -08:00
Frederick F. Kautz IV 5878dd5e50 Cleaning up more code, system generated by config 2014-11-06 22:45:27 -08:00
Harshavardhana 2011cffe8a Merge pull request #13 from fkautz/pr_out_adding_get_and_put_methods_for_gateway
Adding GET and PUT methods for gateway
2014-11-06 19:33:45 -08:00
Frederick F. Kautz IV 1bf6fe1f68 Adding GET and PUT methods for gateway 2014-11-06 19:32:35 -08:00
Anand Babu (AB) Periasamy 58859a0ecc Merge pull request #12 from fkautz/pr_out_adding_bucket_management_system_with_in_memory_storage_driver
Adding bucket management system with in memory storage driver
2014-11-06 18:36:13 -08:00
Frederick F. Kautz IV 0c68f52caf Adding bucket management system with in memory storage driver 2014-11-06 21:34:46 -05:00
Anand Babu (AB) Periasamy bd99a2185e Merge pull request #11 from fkautz/pr_out_removing_unneeded_entries_from_gitignore
Removing unneeded entries from gitignore
2014-11-04 00:19:56 -08:00
Frederick F. Kautz IV f46a32c963 Removing unneeded entries from gitignore 2014-11-04 00:19:20 -08:00
Anand Babu (AB) Periasamy 129a052fa1 Merge pull request #10 from fkautz/pr_out_moving_to_godep_for_dependency_management
Moving to godep for dependency management
2014-11-03 21:29:40 -08:00
Frederick F. Kautz IV e98a77ff1a Moving to godep for dependency management 2014-11-03 20:59:07 -08:00
Harshavardhana 74f989e3ce Merge pull request #9 from fkautz/pr_out_adding_bucket_and_object_route_in_gateway
Adding bucket and object route in gateway
2014-11-02 21:55:52 -08:00
Frederick F. Kautz IV 0d4ab562af Adding bucket and object route in gateway 2014-11-02 19:55:12 -08:00
Anand Babu (AB) Periasamy 428f012830 Merge pull request #8 from fkautz/pr_out_setting_up_initial_cli_options_and_http_handlers
Setting up initial cli options and http handlers
2014-11-02 18:52:31 -08:00
Frederick F. Kautz IV fc6a2a45cb Setting up initial cli options and http handlers 2014-11-02 17:33:40 -08:00
Anand Babu (AB) Periasamy d02e148236 Merge pull request #7 from fkautz/pr_out_adding_framework_for_cli_options
Adding framework for cli options
2014-11-02 12:26:46 -08:00
Frederick F. Kautz IV 9544ed7b97 Adding framework for cli options 2014-11-02 15:06:26 -05:00
Frederick F. Kautz IV f7efb69fac Merge commit '2cd9d9073e6e7afa19d969269002886532492dd1' as 'third_party/src/github.com/codegangsta/cli' 2014-11-02 14:54:31 -05:00
Frederick F. Kautz IV 2cd9d9073e Squashed 'third_party/src/github.com/codegangsta/cli/' content from commit f7ebb76
git-subtree-dir: third_party/src/github.com/codegangsta/cli
git-subtree-split: f7ebb761e83e21225d1d8954fde853bf8edd46c4
2014-11-02 14:54:31 -05:00
Harshavardhana a5b7ff1175 Merge pull request #6 from fkautz/pr_out_refactoring_miniosd_and_minios_to_a_single_binary_minio
Refactoring miniosd and minios to a single binary minio
2014-11-02 11:35:00 -08:00
Frederick F. Kautz IV dca2f84bc9 Refactoring miniosd and minios to a single binary minio 2014-11-02 14:33:53 -05:00
Harshavardhana 631b3bbf2e Merge pull request #5 from fkautz/pr_out_miniosd_is_now_an_http_server_responds_with_hello_world_at_root
miniosd is now an http server, responds with hello world at root.
2014-11-02 02:06:11 -08:00
Frederick F. Kautz IV e58cada88c miniosd is now an http server, responds with hello world at root. 2014-11-01 21:55:13 -07:00
Frederick F. Kautz IV ddefc424ce Merge pull request #4 from fkautz/pr_out_working_build_system_builds_gopath_dynamically 2014-11-02 00:06:53 -04:00
Frederick F. Kautz IV 111b2639cd Merge commit '4aa2e2eaa01e04e05cfbcd765afb5059ff85b8e1' as 'third_party/src/github.com/gorilla/context' 2014-11-01 21:03:30 -07:00
Frederick F. Kautz IV 4aa2e2eaa0 Squashed 'third_party/src/github.com/gorilla/context/' content from commit 14f550f
git-subtree-dir: third_party/src/github.com/gorilla/context
git-subtree-split: 14f550f51af52180c2eefed15e5fd18d63c0a64a
2014-11-01 21:03:30 -07:00
Frederick F. Kautz IV a17126e581 Merge commit '00f86a28a8d65dd0be9e5f2296e654390c2def31' as 'third_party/src/github.com/gorilla/mux' 2014-11-01 21:02:55 -07:00
Frederick F. Kautz IV 00f86a28a8 Squashed 'third_party/src/github.com/gorilla/mux/' content from commit e444e69
git-subtree-dir: third_party/src/github.com/gorilla/mux
git-subtree-split: e444e69cbd2e2e3e0749a2f3c717cec491552bbf
2014-11-01 21:02:55 -07:00
Frederick F. Kautz IV 2c73655b7c Working build system, builds gopath dynamically 2014-11-01 19:44:30 -07:00
Harshavardhana 1303e5aae7 Merge pull request #3 from fkautz/pr_out_squashed_third_party_src_github_com_geertjohan_go_linenoise_content_from_commit_5d5d527
Squashed 'third_party/src/github.com/GeertJohan/go.linenoise/' content from commit 5d5d527
2014-11-01 16:00:01 -07:00
Frederick F. Kautz IV aeb2497bd3 Removing contrib/linenoise, since it is in third_party golang repo now 2014-11-01 15:46:51 -07:00
Frederick F. Kautz IV d5897cc03a Merge commit '0a65e23e3aead7caea3d3a35fa917da921257dc6' as 'third_party/src/github.com/GeertJohan/go.linenoise' 2014-11-01 15:38:01 -07:00
Frederick F. Kautz IV 0a65e23e3a Squashed 'third_party/src/github.com/GeertJohan/go.linenoise/' content from commit 5d5d527
git-subtree-dir: third_party/src/github.com/GeertJohan/go.linenoise
git-subtree-split: 5d5d5277d975f40b12167b478c0d79df00bda5a8
2014-11-01 15:38:01 -07:00
Anand Babu (AB) Periasamy 999283e75d Merge pull request #2 from fkautz/pr_out_adding_third_party_dir_support
Adding third_party dir support
2014-11-01 15:26:51 -07:00
Frederick F. Kautz IV 26aad4eab2 Adding third_party dir support 2014-11-01 15:20:59 -07:00
Harshavardhana 92f7a91703 Merge pull request #1 from fkautz/pr_out_adding_initial_makefile_and_main_go
Adding initial makefile and main.go
2014-11-01 02:58:00 -07:00
Frederick F. Kautz IV 720ccbddee Adding initial makefile and main.go 2014-11-01 04:22:16 -04:00
Harshavardhana 2acc68d1af Squashed 'contrib/signify/' content from commit a1554a4
git-subtree-dir: contrib/signify
git-subtree-split: a1554a4384c794c004da70bd006ce93101f77426
2014-10-30 22:28:37 -07:00
Harshavardhana e91caac870 Merge commit '2acc68d1af798affc64978ed98abf0be6ebda067' as 'contrib/signify' 2014-10-30 22:28:37 -07:00
Harshavardhana be262e7539 Merge commit '13412ca164f715e89e0eb156599ce5f6e978205c' as 'contrib/linenoise' 2014-10-30 22:26:07 -07:00
Harshavardhana 13412ca164 Squashed 'contrib/linenoise/' content from commit 5d5d527
git-subtree-dir: contrib/linenoise
git-subtree-split: 5d5d5277d975f40b12167b478c0d79df00bda5a8
2014-10-30 22:22:47 -07:00
Harshavardhana 397b887a87 Initial commit 2014-10-30 21:51:52 -07:00
342 changed files with 80894 additions and 2337 deletions
+1
View File
@@ -0,0 +1 @@
main.go ident
+12
View File
@@ -0,0 +1,12 @@
/build-constants.go
**/*.swp
cover.out
*~
minio
!*/
site/
**/*.test
**/*.sublime-workspace
/.idea/
/Minio.iml
**/access.log
+15
View File
@@ -0,0 +1,15 @@
# Generate CONTRIBUTORS.md: contributors.sh
# Tip for finding duplicates (besides scanning the output of CONTRIBUTORS.md for name
# duplicates that aren't also email duplicates): scan the output of:
# git log --format='%aE - %aN' | sort -uf
#
# For explanation on this file format: man git-shortlog
Anand Babu (AB) Periasamy <ab@unlocksmith.org> <abperiasamy@users.noreply.github.com>
Anis Elleuch <vadmeste@gmail.com>
Frederick F. Kautz IV <fkautz@minio.io> <fkautz@alumni.cmu.edu>
Harshavardhana <harsha@minio.io> <harsha@harshavardhana.net>
Harshavardhana <harsha@minio.io> <badger@gitter.im>
Harshavardhana <harsha@minio.io>
Matthew Farrellee <matt@cs.wisc.edu>
+16
View File
@@ -0,0 +1,16 @@
language: go
before_install:
- git clone https://github.com/yasm/yasm
- cd yasm
- git checkout v1.2.0
- "./autogen.sh"
- "./configure"
- make
- export PATH=$PATH:`pwd`
- cd ..
sudo: false
go:
- 1.4.2
notifications:
slack:
secure: jlDBuqna7waJXJrl/EOeTH1fXgqJu3WrTDl0Sv7oJBNVH1Af4cGmHaa1oVWrYUMB7lEPjpuF+xcBNA+N+mcR53JbpqueR3sIKlokqHL4TPZBg4XX+1yqtmYMkL6V2woWQ7Wmtis0kDstSoVZjEUVHgk3YF8hcLlK49oMhTeqY08=
+71
View File
@@ -0,0 +1,71 @@
### Install Golang
If you do not have a working Golang environment setup please follow [Golang Installation Guide](./INSTALLGO.md).
### Setup your Minio Github Repository
Fork [Minio upstream](https://github.com/minio/minio/fork) source repository to your own personal repository. Copy the URL and pass it to ``go get`` command. Go uses git to clone a copy into your project workspace folder.
```sh
$ mkdir -p $GOPATH/src/github.com/minio
$ cd $GOPATH/src/github.com/minio
$ git clone https://github.com/$USER_ID/minio
$ cd minio
```
### Compiling Minio from source
Minio uses ``Makefile`` to wrap around some of the limitations of ``go`` build system. To compile Minio source, simply change to your workspace folder and type ``make``.
```sh
$ make
Checking if proper environment variables are set.. Done
...
Checking dependencies for Minio.. Done
Installed godep
Installed cover
Building Libraries
...
...
```
### Setting up git remote as ``upstream``
```sh
$ cd $GOPATH/src/github.com/minio/minio
$ git remote add upstream https://github.com/minio/minio
$ git fetch upstream
$ git merge upstream/master
...
...
$ make
Checking if proper environment variables are set.. Done
...
Checking dependencies for Minio.. Done
Installed godep
Installed cover
Building Libraries
...
```
### Developer Guidelines
``Minio`` community welcomes your contribution. To make the process as seamless as possible, we ask for the following:
* Go ahead and fork the project and make your changes. We encourage pull requests to discuss code changes.
- Fork it
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create new Pull Request
* If you have additional dependencies for ``Minio``, ``Minio`` manages its depedencies using [godep](https://github.com/tools/godep)
- Run `go get foo/bar`
- Edit your code to import foo/bar
- Run `make save` from top-level directory (or `godep restore && godep save ./...`).
* When you're ready to create a pull request, be sure to:
- Have test cases for the new code. If you have questions about how to do it, please ask in your pull request.
- Run `go fmt
- Run `golint`
```
$ go get github.com/golang/lint/golint
$ golint ./...
```
- Squash your commits into a single commit. `git rebase -i`. It's okay to force update your pull request.
- Make sure `go test -race ./...` and `go build` completes.
* Read [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project
- `Minio` project is strictly conformant with Golang style
- if you happen to observe offending code, please feel free to send a pull request
+8
View File
@@ -0,0 +1,8 @@
## Contributors
<!-- DO NOT EDIT - CONTRIBUTORS.md is autogenerated from git commit log by contributors.sh script. -->
- Anand Babu (AB) Periasamy <ab@unlocksmith.org>
- Anis Elleuch <vadmeste@gmail.com>
- Frederick F. Kautz IV <fkautz@minio.io>
- Harshavardhana <harsha@minio.io>
- Matthew Farrellee <matt@cs.wisc.edu>
+34
View File
@@ -0,0 +1,34 @@
FROM ubuntu:14.04
MAINTAINER Minio Community
ENV GOLANG_TARBALL go1.4.2.linux-amd64.tar.gz
ENV GOROOT /usr/local/go/
ENV GOPATH /go-workspace
ENV PATH ${GOROOT}/bin:${GOPATH}/bin/:$PATH
RUN apt-get update -y && apt-get install -y -q \
curl \
git \
build-essential \
ca-certificates \
yasm
RUN curl -O -s https://storage.googleapis.com/golang/${GOLANG_TARBALL} && \
tar -xzf ${GOLANG_TARBALL} -C ${GOROOT%*go*} && \
rm ${GOLANG_TARBALL}
ADD . ${GOPATH}/src/github.com/minio/minio
RUN cd ${GOPATH}/src/github.com/minio/minio && \
make
RUN apt-get remove -y build-essential curl git && \
apt-get -y autoremove && \
rm -rf /var/lib/apt/lists/*
EXPOSE 9000 9001
CMD ["sh", "-c", "${GOPATH}/bin/minio mode memory 2G"]
+42
View File
@@ -0,0 +1,42 @@
{
"ImportPath": "github.com/minio/minio",
"GoVersion": "go1.4",
"Packages": [
"./..."
],
"Deps": [
{
"ImportPath": "github.com/dustin/go-humanize",
"Rev": "8cc1aaa2d955ee82833337cfb10babc42be6bce6"
},
{
"ImportPath": "github.com/gorilla/context",
"Rev": "50c25fb3b2b3b3cc724e9b6ac75fb44b3bccd0da"
},
{
"ImportPath": "github.com/gorilla/mux",
"Rev": "e444e69cbd2e2e3e0749a2f3c717cec491552bbf"
},
{
"ImportPath": "github.com/minio/check",
"Rev": "67f8c16c6c27bb03c82e41c2be533ace00035ab4"
},
{
"ImportPath": "github.com/minio/cli",
"Comment": "1.2.0-112-g823349c",
"Rev": "823349ce91e76834a4af0119d5bbc58fd4d2c6b0"
},
{
"ImportPath": "github.com/stretchr/objx",
"Rev": "cbeaeb16a013161a98496fad62933b1d21786672"
},
{
"ImportPath": "github.com/stretchr/testify/assert",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
},
{
"ImportPath": "github.com/stretchr/testify/mock",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
}
]
}
Generated
+5
View File
@@ -0,0 +1,5 @@
This directory tree is generated automatically by godep.
Please do not edit.
See https://github.com/tools/godep for more information.
+2
View File
@@ -0,0 +1,2 @@
/pkg
/bin
@@ -0,0 +1,6 @@
#*
*.[568]
*.a
*~
[568].out
_*
+21
View File
@@ -0,0 +1,21 @@
Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
<http://www.opensource.org/licenses/mit-license.php>
+78
View File
@@ -0,0 +1,78 @@
# Humane Units
Just a few functions for helping humanize times and sizes.
`go get` it as `github.com/dustin/go-humanize`, import it as
`"github.com/dustin/go-humanize"`, use it as `humanize`
## Sizes
This lets you take numbers like `82854982` and convert them to useful
strings like, `83MB` or `79MiB` (whichever you prefer).
Example:
fmt.Printf("That file is %s.", humanize.Bytes(82854982))
## Times
This lets you take a `time.Time` and spit it out in relative terms.
For example, `12 seconds ago` or `3 days from now`.
Example:
fmt.Printf("This was touched %s", humanize.Time(someTimeInstance))
Thanks to Kyle Lemons for the time implementation from an IRC
conversation one day. It's pretty neat.
## Ordinals
From a [mailing list discussion][odisc] where a user wanted to be able
to label ordinals.
0 -> 0th
1 -> 1st
2 -> 2nd
3 -> 3rd
4 -> 4th
[...]
Example:
fmt.Printf("You're my %s best friend.", humanize.Ordinal(193))
## Commas
Want to shove commas into numbers? Be my guest.
0 -> 0
100 -> 100
1000 -> 1,000
1000000000 -> 1,000,000,000
-100000 -> -100,000
Example:
fmt.Printf("You owe $%s.\n", humanize.Comma(6582491))
## Ftoa
Nicer float64 formatter that removes trailing zeros.
fmt.Printf("%f", 2.24) // 2.240000
fmt.Printf("%s", humanize.Ftoa(2.24)) // 2.24
fmt.Printf("%f", 2.0) // 2.000000
fmt.Printf("%s", humanize.Ftoa(2.0)) // 2
## SI notation
Format numbers with [SI notation][sinotation].
Example:
humanize.SI(0.00000000223, "M") // 2.23nM
[odisc]: https://groups.google.com/d/topic/golang-nuts/l8NhI74jl-4/discussion
[sinotation]: http://en.wikipedia.org/wiki/Metric_prefix
+31
View File
@@ -0,0 +1,31 @@
package humanize
import (
"math/big"
)
// order of magnitude (to a max order)
func oomm(n, b *big.Int, maxmag int) (float64, int) {
mag := 0
m := &big.Int{}
for n.Cmp(b) >= 0 {
n.DivMod(n, b, m)
mag++
if mag == maxmag && maxmag >= 0 {
break
}
}
return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag
}
// total order of magnitude
// (same as above, but with no upper limit)
func oom(n, b *big.Int) (float64, int) {
mag := 0
m := &big.Int{}
for n.Cmp(b) >= 0 {
n.DivMod(n, b, m)
mag++
}
return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag
}
+164
View File
@@ -0,0 +1,164 @@
package humanize
import (
"fmt"
"math/big"
"strings"
"unicode"
)
var (
bigIECExp = big.NewInt(1024)
// BigByte is one byte in bit.Ints
BigByte = big.NewInt(1)
// BigKiByte is 1,024 bytes in bit.Ints
BigKiByte = (&big.Int{}).Mul(BigByte, bigIECExp)
// BigMiByte is 1,024 k bytes in bit.Ints
BigMiByte = (&big.Int{}).Mul(BigKiByte, bigIECExp)
// BigGiByte is 1,024 m bytes in bit.Ints
BigGiByte = (&big.Int{}).Mul(BigMiByte, bigIECExp)
// BigTiByte is 1,024 g bytes in bit.Ints
BigTiByte = (&big.Int{}).Mul(BigGiByte, bigIECExp)
// BigPiByte is 1,024 t bytes in bit.Ints
BigPiByte = (&big.Int{}).Mul(BigTiByte, bigIECExp)
// BigEiByte is 1,024 p bytes in bit.Ints
BigEiByte = (&big.Int{}).Mul(BigPiByte, bigIECExp)
// BigZiByte is 1,024 e bytes in bit.Ints
BigZiByte = (&big.Int{}).Mul(BigEiByte, bigIECExp)
// BigYiByte is 1,024 z bytes in bit.Ints
BigYiByte = (&big.Int{}).Mul(BigZiByte, bigIECExp)
)
var (
bigSIExp = big.NewInt(1000)
// BigSIByte is one SI byte in big.Ints
BigSIByte = big.NewInt(1)
// BigKByte is 1,000 SI bytes in big.Ints
BigKByte = (&big.Int{}).Mul(BigSIByte, bigSIExp)
// BigMByte is 1,000 SI k bytes in big.Ints
BigMByte = (&big.Int{}).Mul(BigKByte, bigSIExp)
// BigGByte is 1,000 SI m bytes in big.Ints
BigGByte = (&big.Int{}).Mul(BigMByte, bigSIExp)
// BigTByte is 1,000 SI g bytes in big.Ints
BigTByte = (&big.Int{}).Mul(BigGByte, bigSIExp)
// BigPByte is 1,000 SI t bytes in big.Ints
BigPByte = (&big.Int{}).Mul(BigTByte, bigSIExp)
// BigEByte is 1,000 SI p bytes in big.Ints
BigEByte = (&big.Int{}).Mul(BigPByte, bigSIExp)
// BigZByte is 1,000 SI e bytes in big.Ints
BigZByte = (&big.Int{}).Mul(BigEByte, bigSIExp)
// BigYByte is 1,000 SI z bytes in big.Ints
BigYByte = (&big.Int{}).Mul(BigZByte, bigSIExp)
)
var bigBytesSizeTable = map[string]*big.Int{
"b": BigByte,
"kib": BigKiByte,
"kb": BigKByte,
"mib": BigMiByte,
"mb": BigMByte,
"gib": BigGiByte,
"gb": BigGByte,
"tib": BigTiByte,
"tb": BigTByte,
"pib": BigPiByte,
"pb": BigPByte,
"eib": BigEiByte,
"eb": BigEByte,
"zib": BigZiByte,
"zb": BigZByte,
"yib": BigYiByte,
"yb": BigYByte,
// Without suffix
"": BigByte,
"ki": BigKiByte,
"k": BigKByte,
"mi": BigMiByte,
"m": BigMByte,
"gi": BigGiByte,
"g": BigGByte,
"ti": BigTiByte,
"t": BigTByte,
"pi": BigPiByte,
"p": BigPByte,
"ei": BigEiByte,
"e": BigEByte,
"z": BigZByte,
"zi": BigZiByte,
"y": BigYByte,
"yi": BigYiByte,
}
var ten = big.NewInt(10)
func humanateBigBytes(s, base *big.Int, sizes []string) string {
if s.Cmp(ten) < 0 {
return fmt.Sprintf("%dB", s)
}
c := (&big.Int{}).Set(s)
val, mag := oomm(c, base, len(sizes)-1)
suffix := sizes[mag]
f := "%.0f%s"
if val < 10 {
f = "%.1f%s"
}
return fmt.Sprintf(f, val, suffix)
}
// BigBytes produces a human readable representation of an SI size.
//
// See also: ParseBigBytes.
//
// BigBytes(82854982) -> 83MB
func BigBytes(s *big.Int) string {
sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
return humanateBigBytes(s, bigSIExp, sizes)
}
// BigIBytes produces a human readable representation of an IEC size.
//
// See also: ParseBigBytes.
//
// BigIBytes(82854982) -> 79MiB
func BigIBytes(s *big.Int) string {
sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
return humanateBigBytes(s, bigIECExp, sizes)
}
// ParseBigBytes parses a string representation of bytes into the number
// of bytes it represents.
//
// See also: BigBytes, BigIBytes.
//
// ParseBigBytes("42MB") -> 42000000, nil
// ParseBigBytes("42mib") -> 44040192, nil
func ParseBigBytes(s string) (*big.Int, error) {
lastDigit := 0
for _, r := range s {
if !(unicode.IsDigit(r) || r == '.') {
break
}
lastDigit++
}
val := &big.Rat{}
_, err := fmt.Sscanf(s[:lastDigit], "%f", val)
if err != nil {
return nil, err
}
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
if m, ok := bigBytesSizeTable[extra]; ok {
mv := (&big.Rat{}).SetInt(m)
val.Mul(val, mv)
rv := &big.Int{}
rv.Div(val.Num(), val.Denom())
return rv, nil
}
return nil, fmt.Errorf("unhandled size name: %v", extra)
}
+219
View File
@@ -0,0 +1,219 @@
package humanize
import (
"math/big"
"testing"
)
func TestBigByteParsing(t *testing.T) {
tests := []struct {
in string
exp uint64
}{
{"42", 42},
{"42MB", 42000000},
{"42MiB", 44040192},
{"42mb", 42000000},
{"42mib", 44040192},
{"42MIB", 44040192},
{"42 MB", 42000000},
{"42 MiB", 44040192},
{"42 mb", 42000000},
{"42 mib", 44040192},
{"42 MIB", 44040192},
{"42.5MB", 42500000},
{"42.5MiB", 44564480},
{"42.5 MB", 42500000},
{"42.5 MiB", 44564480},
// No need to say B
{"42M", 42000000},
{"42Mi", 44040192},
{"42m", 42000000},
{"42mi", 44040192},
{"42MI", 44040192},
{"42 M", 42000000},
{"42 Mi", 44040192},
{"42 m", 42000000},
{"42 mi", 44040192},
{"42 MI", 44040192},
{"42.5M", 42500000},
{"42.5Mi", 44564480},
{"42.5 M", 42500000},
{"42.5 Mi", 44564480},
// Large testing, breaks when too much larger than
// this.
{"12.5 EB", uint64(12.5 * float64(EByte))},
{"12.5 E", uint64(12.5 * float64(EByte))},
{"12.5 EiB", uint64(12.5 * float64(EiByte))},
}
for _, p := range tests {
got, err := ParseBigBytes(p.in)
if err != nil {
t.Errorf("Couldn't parse %v: %v", p.in, err)
} else {
if got.Uint64() != p.exp {
t.Errorf("Expected %v for %v, got %v",
p.exp, p.in, got)
}
}
}
}
func TestBigByteErrors(t *testing.T) {
got, err := ParseBigBytes("84 JB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
got, err = ParseBigBytes("")
if err == nil {
t.Errorf("Expected error parsing nothing")
}
}
func bbyte(in uint64) string {
return BigBytes((&big.Int{}).SetUint64(in))
}
func bibyte(in uint64) string {
return BigIBytes((&big.Int{}).SetUint64(in))
}
func TestBigBytes(t *testing.T) {
testList{
{"bytes(0)", bbyte(0), "0B"},
{"bytes(1)", bbyte(1), "1B"},
{"bytes(803)", bbyte(803), "803B"},
{"bytes(999)", bbyte(999), "999B"},
{"bytes(1024)", bbyte(1024), "1.0KB"},
{"bytes(1MB - 1)", bbyte(MByte - Byte), "1000KB"},
{"bytes(1MB)", bbyte(1024 * 1024), "1.0MB"},
{"bytes(1GB - 1K)", bbyte(GByte - KByte), "1000MB"},
{"bytes(1GB)", bbyte(GByte), "1.0GB"},
{"bytes(1TB - 1M)", bbyte(TByte - MByte), "1000GB"},
{"bytes(1TB)", bbyte(TByte), "1.0TB"},
{"bytes(1PB - 1T)", bbyte(PByte - TByte), "999TB"},
{"bytes(1PB)", bbyte(PByte), "1.0PB"},
{"bytes(1PB - 1T)", bbyte(EByte - PByte), "999PB"},
{"bytes(1EB)", bbyte(EByte), "1.0EB"},
// Overflows.
// {"bytes(1EB - 1P)", Bytes((KByte*EByte)-PByte), "1023EB"},
{"bytes(0)", bibyte(0), "0B"},
{"bytes(1)", bibyte(1), "1B"},
{"bytes(803)", bibyte(803), "803B"},
{"bytes(1023)", bibyte(1023), "1023B"},
{"bytes(1024)", bibyte(1024), "1.0KiB"},
{"bytes(1MB - 1)", bibyte(MiByte - IByte), "1024KiB"},
{"bytes(1MB)", bibyte(1024 * 1024), "1.0MiB"},
{"bytes(1GB - 1K)", bibyte(GiByte - KiByte), "1024MiB"},
{"bytes(1GB)", bibyte(GiByte), "1.0GiB"},
{"bytes(1TB - 1M)", bibyte(TiByte - MiByte), "1024GiB"},
{"bytes(1TB)", bibyte(TiByte), "1.0TiB"},
{"bytes(1PB - 1T)", bibyte(PiByte - TiByte), "1023TiB"},
{"bytes(1PB)", bibyte(PiByte), "1.0PiB"},
{"bytes(1PB - 1T)", bibyte(EiByte - PiByte), "1023PiB"},
{"bytes(1EiB)", bibyte(EiByte), "1.0EiB"},
// Overflows.
// {"bytes(1EB - 1P)", bibyte((KIByte*EIByte)-PiByte), "1023EB"},
{"bytes(5.5GiB)", bibyte(5.5 * GiByte), "5.5GiB"},
{"bytes(5.5GB)", bbyte(5.5 * GByte), "5.5GB"},
}.validate(t)
}
func TestVeryBigBytes(t *testing.T) {
b, _ := (&big.Int{}).SetString("15347691069326346944512", 10)
s := BigBytes(b)
if s != "15ZB" {
t.Errorf("Expected 15ZB, got %v", s)
}
s = BigIBytes(b)
if s != "13ZiB" {
t.Errorf("Expected 13ZiB, got %v", s)
}
b, _ = (&big.Int{}).SetString("15716035654990179271180288", 10)
s = BigBytes(b)
if s != "16YB" {
t.Errorf("Expected 16YB, got %v", s)
}
s = BigIBytes(b)
if s != "13YiB" {
t.Errorf("Expected 13YiB, got %v", s)
}
}
func TestVeryVeryBigBytes(t *testing.T) {
b, _ := (&big.Int{}).SetString("16093220510709943573688614912", 10)
s := BigBytes(b)
if s != "16093YB" {
t.Errorf("Expected 16093YB, got %v", s)
}
s = BigIBytes(b)
if s != "13312YiB" {
t.Errorf("Expected 13312YiB, got %v", s)
}
}
func TestParseVeryBig(t *testing.T) {
tests := []struct {
in string
out string
}{
{"16ZB", "16000000000000000000000"},
{"16ZiB", "18889465931478580854784"},
{"16.5ZB", "16500000000000000000000"},
{"16.5ZiB", "19479761741837286506496"},
{"16Z", "16000000000000000000000"},
{"16Zi", "18889465931478580854784"},
{"16.5Z", "16500000000000000000000"},
{"16.5Zi", "19479761741837286506496"},
{"16YB", "16000000000000000000000000"},
{"16YiB", "19342813113834066795298816"},
{"16.5YB", "16500000000000000000000000"},
{"16.5YiB", "19947276023641381382651904"},
{"16Y", "16000000000000000000000000"},
{"16Yi", "19342813113834066795298816"},
{"16.5Y", "16500000000000000000000000"},
{"16.5Yi", "19947276023641381382651904"},
}
for _, test := range tests {
x, err := ParseBigBytes(test.in)
if err != nil {
t.Errorf("Error parsing %q: %v", test.in, err)
continue
}
if x.String() != test.out {
t.Errorf("Expected %q for %q, got %v", test.out, test.in, x)
}
}
}
func BenchmarkParseBigBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseBigBytes("16.5Z")
}
}
func BenchmarkBigBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
bibyte(16.5 * GByte)
}
}
+134
View File
@@ -0,0 +1,134 @@
package humanize
import (
"fmt"
"math"
"strconv"
"strings"
"unicode"
)
// IEC Sizes.
// kibis of bits
const (
Byte = 1 << (iota * 10)
KiByte
MiByte
GiByte
TiByte
PiByte
EiByte
)
// SI Sizes.
const (
IByte = 1
KByte = IByte * 1000
MByte = KByte * 1000
GByte = MByte * 1000
TByte = GByte * 1000
PByte = TByte * 1000
EByte = PByte * 1000
)
var bytesSizeTable = map[string]uint64{
"b": Byte,
"kib": KiByte,
"kb": KByte,
"mib": MiByte,
"mb": MByte,
"gib": GiByte,
"gb": GByte,
"tib": TiByte,
"tb": TByte,
"pib": PiByte,
"pb": PByte,
"eib": EiByte,
"eb": EByte,
// Without suffix
"": Byte,
"ki": KiByte,
"k": KByte,
"mi": MiByte,
"m": MByte,
"gi": GiByte,
"g": GByte,
"ti": TiByte,
"t": TByte,
"pi": PiByte,
"p": PByte,
"ei": EiByte,
"e": EByte,
}
func logn(n, b float64) float64 {
return math.Log(n) / math.Log(b)
}
func humanateBytes(s uint64, base float64, sizes []string) string {
if s < 10 {
return fmt.Sprintf("%dB", s)
}
e := math.Floor(logn(float64(s), base))
suffix := sizes[int(e)]
val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
f := "%.0f%s"
if val < 10 {
f = "%.1f%s"
}
return fmt.Sprintf(f, val, suffix)
}
// Bytes produces a human readable representation of an SI size.
//
// See also: ParseBytes.
//
// Bytes(82854982) -> 83MB
func Bytes(s uint64) string {
sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
return humanateBytes(s, 1000, sizes)
}
// IBytes produces a human readable representation of an IEC size.
//
// See also: ParseBytes.
//
// IBytes(82854982) -> 79MiB
func IBytes(s uint64) string {
sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
return humanateBytes(s, 1024, sizes)
}
// ParseBytes parses a string representation of bytes into the number
// of bytes it represents.
//
// See Also: Bytes, IBytes.
//
// ParseBytes("42MB") -> 42000000, nil
// ParseBytes("42mib") -> 44040192, nil
func ParseBytes(s string) (uint64, error) {
lastDigit := 0
for _, r := range s {
if !(unicode.IsDigit(r) || r == '.') {
break
}
lastDigit++
}
f, err := strconv.ParseFloat(s[:lastDigit], 64)
if err != nil {
return 0, err
}
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
if m, ok := bytesSizeTable[extra]; ok {
f *= float64(m)
if f >= math.MaxUint64 {
return 0, fmt.Errorf("too large: %v", s)
}
return uint64(f), nil
}
return 0, fmt.Errorf("unhandled size name: %v", extra)
}
+144
View File
@@ -0,0 +1,144 @@
package humanize
import (
"testing"
)
func TestByteParsing(t *testing.T) {
tests := []struct {
in string
exp uint64
}{
{"42", 42},
{"42MB", 42000000},
{"42MiB", 44040192},
{"42mb", 42000000},
{"42mib", 44040192},
{"42MIB", 44040192},
{"42 MB", 42000000},
{"42 MiB", 44040192},
{"42 mb", 42000000},
{"42 mib", 44040192},
{"42 MIB", 44040192},
{"42.5MB", 42500000},
{"42.5MiB", 44564480},
{"42.5 MB", 42500000},
{"42.5 MiB", 44564480},
// No need to say B
{"42M", 42000000},
{"42Mi", 44040192},
{"42m", 42000000},
{"42mi", 44040192},
{"42MI", 44040192},
{"42 M", 42000000},
{"42 Mi", 44040192},
{"42 m", 42000000},
{"42 mi", 44040192},
{"42 MI", 44040192},
{"42.5M", 42500000},
{"42.5Mi", 44564480},
{"42.5 M", 42500000},
{"42.5 Mi", 44564480},
// Large testing, breaks when too much larger than
// this.
{"12.5 EB", uint64(12.5 * float64(EByte))},
{"12.5 E", uint64(12.5 * float64(EByte))},
{"12.5 EiB", uint64(12.5 * float64(EiByte))},
}
for _, p := range tests {
got, err := ParseBytes(p.in)
if err != nil {
t.Errorf("Couldn't parse %v: %v", p.in, err)
}
if got != p.exp {
t.Errorf("Expected %v for %v, got %v",
p.exp, p.in, got)
}
}
}
func TestByteErrors(t *testing.T) {
got, err := ParseBytes("84 JB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
got, err = ParseBytes("")
if err == nil {
t.Errorf("Expected error parsing nothing")
}
got, err = ParseBytes("16 EiB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
}
func TestBytes(t *testing.T) {
testList{
{"bytes(0)", Bytes(0), "0B"},
{"bytes(1)", Bytes(1), "1B"},
{"bytes(803)", Bytes(803), "803B"},
{"bytes(999)", Bytes(999), "999B"},
{"bytes(1024)", Bytes(1024), "1.0KB"},
{"bytes(9999)", Bytes(9999), "10KB"},
{"bytes(1MB - 1)", Bytes(MByte - Byte), "1000KB"},
{"bytes(1MB)", Bytes(1024 * 1024), "1.0MB"},
{"bytes(1GB - 1K)", Bytes(GByte - KByte), "1000MB"},
{"bytes(1GB)", Bytes(GByte), "1.0GB"},
{"bytes(1TB - 1M)", Bytes(TByte - MByte), "1000GB"},
{"bytes(10MB)", Bytes(9999 * 1000), "10MB"},
{"bytes(1TB)", Bytes(TByte), "1.0TB"},
{"bytes(1PB - 1T)", Bytes(PByte - TByte), "999TB"},
{"bytes(1PB)", Bytes(PByte), "1.0PB"},
{"bytes(1PB - 1T)", Bytes(EByte - PByte), "999PB"},
{"bytes(1EB)", Bytes(EByte), "1.0EB"},
// Overflows.
// {"bytes(1EB - 1P)", Bytes((KByte*EByte)-PByte), "1023EB"},
{"bytes(0)", IBytes(0), "0B"},
{"bytes(1)", IBytes(1), "1B"},
{"bytes(803)", IBytes(803), "803B"},
{"bytes(1023)", IBytes(1023), "1023B"},
{"bytes(1024)", IBytes(1024), "1.0KiB"},
{"bytes(1MB - 1)", IBytes(MiByte - IByte), "1024KiB"},
{"bytes(1MB)", IBytes(1024 * 1024), "1.0MiB"},
{"bytes(1GB - 1K)", IBytes(GiByte - KiByte), "1024MiB"},
{"bytes(1GB)", IBytes(GiByte), "1.0GiB"},
{"bytes(1TB - 1M)", IBytes(TiByte - MiByte), "1024GiB"},
{"bytes(1TB)", IBytes(TiByte), "1.0TiB"},
{"bytes(1PB - 1T)", IBytes(PiByte - TiByte), "1023TiB"},
{"bytes(1PB)", IBytes(PiByte), "1.0PiB"},
{"bytes(1PB - 1T)", IBytes(EiByte - PiByte), "1023PiB"},
{"bytes(1EiB)", IBytes(EiByte), "1.0EiB"},
// Overflows.
// {"bytes(1EB - 1P)", IBytes((KIByte*EIByte)-PiByte), "1023EB"},
{"bytes(5.5GiB)", IBytes(5.5 * GiByte), "5.5GiB"},
{"bytes(5.5GB)", Bytes(5.5 * GByte), "5.5GB"},
}.validate(t)
}
func BenchmarkParseBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseBytes("16.5GB")
}
}
func BenchmarkBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
Bytes(16.5 * GByte)
}
}
+101
View File
@@ -0,0 +1,101 @@
package humanize
import (
"bytes"
"math/big"
"strconv"
"strings"
)
// Comma produces a string form of the given number in base 10 with
// commas after every three orders of magnitude.
//
// e.g. Comma(834142) -> 834,142
func Comma(v int64) string {
sign := ""
if v < 0 {
sign = "-"
v = 0 - v
}
parts := []string{"", "", "", "", "", "", "", ""}
j := len(parts) - 1
for v > 999 {
parts[j] = strconv.FormatInt(v%1000, 10)
switch len(parts[j]) {
case 2:
parts[j] = "0" + parts[j]
case 1:
parts[j] = "00" + parts[j]
}
v = v / 1000
j--
}
parts[j] = strconv.Itoa(int(v))
return sign + strings.Join(parts[j:len(parts)], ",")
}
// Commaf produces a string form of the given number in base 10 with
// commas after every three orders of magnitude.
//
// e.g. Comma(834142.32) -> 834,142.32
func Commaf(v float64) string {
buf := &bytes.Buffer{}
if v < 0 {
buf.Write([]byte{'-'})
v = 0 - v
}
comma := []byte{','}
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
pos := 0
if len(parts[0])%3 != 0 {
pos += len(parts[0]) % 3
buf.WriteString(parts[0][:pos])
buf.Write(comma)
}
for ; pos < len(parts[0]); pos += 3 {
buf.WriteString(parts[0][pos : pos+3])
buf.Write(comma)
}
buf.Truncate(buf.Len() - 1)
if len(parts) > 1 {
buf.Write([]byte{'.'})
buf.WriteString(parts[1])
}
return buf.String()
}
// BigComma produces a string form of the given big.Int in base 10
// with commas after every three orders of magnitude.
func BigComma(b *big.Int) string {
sign := ""
if b.Sign() < 0 {
sign = "-"
b.Abs(b)
}
athousand := big.NewInt(1000)
c := (&big.Int{}).Set(b)
_, m := oom(c, athousand)
parts := make([]string, m+1)
j := len(parts) - 1
mod := &big.Int{}
for b.Cmp(athousand) >= 0 {
b.DivMod(b, athousand, mod)
parts[j] = strconv.FormatInt(mod.Int64(), 10)
switch len(parts[j]) {
case 2:
parts[j] = "0" + parts[j]
case 1:
parts[j] = "00" + parts[j]
}
j--
}
parts[j] = strconv.Itoa(int(b.Int64()))
return sign + strings.Join(parts[j:len(parts)], ",")
}
+134
View File
@@ -0,0 +1,134 @@
package humanize
import (
"math"
"math/big"
"testing"
)
func TestCommas(t *testing.T) {
testList{
{"0", Comma(0), "0"},
{"10", Comma(10), "10"},
{"100", Comma(100), "100"},
{"1,000", Comma(1000), "1,000"},
{"10,000", Comma(10000), "10,000"},
{"100,000", Comma(100000), "100,000"},
{"10,000,000", Comma(10000000), "10,000,000"},
{"10,100,000", Comma(10100000), "10,100,000"},
{"10,010,000", Comma(10010000), "10,010,000"},
{"10,001,000", Comma(10001000), "10,001,000"},
{"123,456,789", Comma(123456789), "123,456,789"},
{"maxint", Comma(9.223372e+18), "9,223,372,000,000,000,000"},
{"minint", Comma(-9.223372e+18), "-9,223,372,000,000,000,000"},
{"-123,456,789", Comma(-123456789), "-123,456,789"},
{"-10,100,000", Comma(-10100000), "-10,100,000"},
{"-10,010,000", Comma(-10010000), "-10,010,000"},
{"-10,001,000", Comma(-10001000), "-10,001,000"},
{"-10,000,000", Comma(-10000000), "-10,000,000"},
{"-100,000", Comma(-100000), "-100,000"},
{"-10,000", Comma(-10000), "-10,000"},
{"-1,000", Comma(-1000), "-1,000"},
{"-100", Comma(-100), "-100"},
{"-10", Comma(-10), "-10"},
}.validate(t)
}
func TestCommafs(t *testing.T) {
testList{
{"0", Commaf(0), "0"},
{"10.11", Commaf(10.11), "10.11"},
{"100", Commaf(100), "100"},
{"1,000", Commaf(1000), "1,000"},
{"10,000", Commaf(10000), "10,000"},
{"100,000", Commaf(100000), "100,000"},
{"834,142.32", Commaf(834142.32), "834,142.32"},
{"10,000,000", Commaf(10000000), "10,000,000"},
{"10,100,000", Commaf(10100000), "10,100,000"},
{"10,010,000", Commaf(10010000), "10,010,000"},
{"10,001,000", Commaf(10001000), "10,001,000"},
{"123,456,789", Commaf(123456789), "123,456,789"},
{"maxf64", Commaf(math.MaxFloat64), "179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000"},
{"minf64", Commaf(math.SmallestNonzeroFloat64), "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005"},
{"-123,456,789", Commaf(-123456789), "-123,456,789"},
{"-10,100,000", Commaf(-10100000), "-10,100,000"},
{"-10,010,000", Commaf(-10010000), "-10,010,000"},
{"-10,001,000", Commaf(-10001000), "-10,001,000"},
{"-10,000,000", Commaf(-10000000), "-10,000,000"},
{"-100,000", Commaf(-100000), "-100,000"},
{"-10,000", Commaf(-10000), "-10,000"},
{"-1,000", Commaf(-1000), "-1,000"},
{"-100.11", Commaf(-100.11), "-100.11"},
{"-10", Commaf(-10), "-10"},
}.validate(t)
}
func BenchmarkCommas(b *testing.B) {
for i := 0; i < b.N; i++ {
Comma(1234567890)
}
}
func BenchmarkCommaf(b *testing.B) {
for i := 0; i < b.N; i++ {
Commaf(1234567890.83584)
}
}
func BenchmarkBigCommas(b *testing.B) {
for i := 0; i < b.N; i++ {
BigComma(big.NewInt(1234567890))
}
}
func bigComma(i int64) string {
return BigComma(big.NewInt(i))
}
func TestBigCommas(t *testing.T) {
testList{
{"0", bigComma(0), "0"},
{"10", bigComma(10), "10"},
{"100", bigComma(100), "100"},
{"1,000", bigComma(1000), "1,000"},
{"10,000", bigComma(10000), "10,000"},
{"100,000", bigComma(100000), "100,000"},
{"10,000,000", bigComma(10000000), "10,000,000"},
{"10,100,000", bigComma(10100000), "10,100,000"},
{"10,010,000", bigComma(10010000), "10,010,000"},
{"10,001,000", bigComma(10001000), "10,001,000"},
{"123,456,789", bigComma(123456789), "123,456,789"},
{"maxint", bigComma(9.223372e+18), "9,223,372,000,000,000,000"},
{"minint", bigComma(-9.223372e+18), "-9,223,372,000,000,000,000"},
{"-123,456,789", bigComma(-123456789), "-123,456,789"},
{"-10,100,000", bigComma(-10100000), "-10,100,000"},
{"-10,010,000", bigComma(-10010000), "-10,010,000"},
{"-10,001,000", bigComma(-10001000), "-10,001,000"},
{"-10,000,000", bigComma(-10000000), "-10,000,000"},
{"-100,000", bigComma(-100000), "-100,000"},
{"-10,000", bigComma(-10000), "-10,000"},
{"-1,000", bigComma(-1000), "-1,000"},
{"-100", bigComma(-100), "-100"},
{"-10", bigComma(-10), "-10"},
}.validate(t)
}
func TestVeryBigCommas(t *testing.T) {
tests := []struct{ in, exp string }{
{
"84889279597249724975972597249849757294578485",
"84,889,279,597,249,724,975,972,597,249,849,757,294,578,485",
},
{
"-84889279597249724975972597249849757294578485",
"-84,889,279,597,249,724,975,972,597,249,849,757,294,578,485",
},
}
for _, test := range tests {
n, _ := (&big.Int{}).SetString(test.in, 10)
got := BigComma(n)
if test.exp != got {
t.Errorf("Expected %q, got %q", test.exp, got)
}
}
}
+18
View File
@@ -0,0 +1,18 @@
package humanize
import (
"testing"
)
type testList []struct {
name, got, exp string
}
func (tl testList) validate(t *testing.T) {
for _, test := range tl {
if test.got != test.exp {
t.Errorf("On %v, expected '%v', but got '%v'",
test.name, test.exp, test.got)
}
}
}
+23
View File
@@ -0,0 +1,23 @@
package humanize
import "strconv"
func stripTrailingZeros(s string) string {
offset := len(s) - 1
for offset > 0 {
if s[offset] == '.' {
offset--
break
}
if s[offset] != '0' {
break
}
offset--
}
return s[:offset+1]
}
// Ftoa converts a float to a string with no trailing zeros.
func Ftoa(num float64) string {
return stripTrailingZeros(strconv.FormatFloat(num, 'f', 6, 64))
}
+55
View File
@@ -0,0 +1,55 @@
package humanize
import (
"fmt"
"regexp"
"strconv"
"testing"
)
func TestFtoa(t *testing.T) {
testList{
{"200", Ftoa(200), "200"},
{"2", Ftoa(2), "2"},
{"2.2", Ftoa(2.2), "2.2"},
{"2.02", Ftoa(2.02), "2.02"},
{"200.02", Ftoa(200.02), "200.02"},
}.validate(t)
}
func BenchmarkFtoaRegexTrailing(b *testing.B) {
trailingZerosRegex := regexp.MustCompile(`\.?0+$`)
b.ResetTimer()
for i := 0; i < b.N; i++ {
trailingZerosRegex.ReplaceAllString("2.00000", "")
trailingZerosRegex.ReplaceAllString("2.0000", "")
trailingZerosRegex.ReplaceAllString("2.000", "")
trailingZerosRegex.ReplaceAllString("2.00", "")
trailingZerosRegex.ReplaceAllString("2.0", "")
trailingZerosRegex.ReplaceAllString("2", "")
}
}
func BenchmarkFtoaFunc(b *testing.B) {
for i := 0; i < b.N; i++ {
stripTrailingZeros("2.00000")
stripTrailingZeros("2.0000")
stripTrailingZeros("2.000")
stripTrailingZeros("2.00")
stripTrailingZeros("2.0")
stripTrailingZeros("2")
}
}
func BenchmarkFmtF(b *testing.B) {
for i := 0; i < b.N; i++ {
fmt.Sprintf("%f", 2.03584)
}
}
func BenchmarkStrconvF(b *testing.B) {
for i := 0; i < b.N; i++ {
strconv.FormatFloat(2.03584, 'f', 6, 64)
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
Package humanize converts boring ugly numbers to human-friendly strings and back.
Durations can be turned into strings such as "3 days ago", numbers
representing sizes like 82854982 into useful strings like, "83MB" or
"79MiB" (whichever you prefer).
*/
package humanize
+25
View File
@@ -0,0 +1,25 @@
package humanize
import "strconv"
// Ordinal gives you the input number in a rank/ordinal format.
//
// Ordinal(3) -> 3rd
func Ordinal(x int) string {
suffix := "th"
switch x % 10 {
case 1:
if x%100 != 11 {
suffix = "st"
}
case 2:
if x%100 != 12 {
suffix = "nd"
}
case 3:
if x%100 != 13 {
suffix = "rd"
}
}
return strconv.Itoa(x) + suffix
}
+22
View File
@@ -0,0 +1,22 @@
package humanize
import (
"testing"
)
func TestOrdinals(t *testing.T) {
testList{
{"0", Ordinal(0), "0th"},
{"1", Ordinal(1), "1st"},
{"2", Ordinal(2), "2nd"},
{"3", Ordinal(3), "3rd"},
{"4", Ordinal(4), "4th"},
{"10", Ordinal(10), "10th"},
{"11", Ordinal(11), "11th"},
{"12", Ordinal(12), "12th"},
{"13", Ordinal(13), "13th"},
{"101", Ordinal(101), "101st"},
{"102", Ordinal(102), "102nd"},
{"103", Ordinal(103), "103rd"},
}.validate(t)
}
+110
View File
@@ -0,0 +1,110 @@
package humanize
import (
"errors"
"math"
"regexp"
"strconv"
)
var siPrefixTable = map[float64]string{
-24: "y", // yocto
-21: "z", // zepto
-18: "a", // atto
-15: "f", // femto
-12: "p", // pico
-9: "n", // nano
-6: "µ", // micro
-3: "m", // milli
0: "",
3: "k", // kilo
6: "M", // mega
9: "G", // giga
12: "T", // tera
15: "P", // peta
18: "E", // exa
21: "Z", // zetta
24: "Y", // yotta
}
var revSIPrefixTable = revfmap(siPrefixTable)
// revfmap reverses the map and precomputes the power multiplier
func revfmap(in map[float64]string) map[string]float64 {
rv := map[string]float64{}
for k, v := range in {
rv[v] = math.Pow(10, k)
}
return rv
}
var riParseRegex *regexp.Regexp
func init() {
ri := `^([0-9.]+)([`
for _, v := range siPrefixTable {
ri += v
}
ri += `]?)(.*)`
riParseRegex = regexp.MustCompile(ri)
}
// ComputeSI finds the most appropriate SI prefix for the given number
// and returns the prefix along with the value adjusted to be within
// that prefix.
//
// See also: SI, ParseSI.
//
// e.g. ComputeSI(2.2345e-12) -> (2.2345, "p")
func ComputeSI(input float64) (float64, string) {
if input == 0 {
return 0, ""
}
exponent := math.Floor(logn(input, 10))
exponent = math.Floor(exponent/3) * 3
value := input / math.Pow(10, exponent)
// Handle special case where value is exactly 1000.0
// Should return 1M instead of 1000k
if value == 1000.0 {
exponent += 3
value = input / math.Pow(10, exponent)
}
prefix := siPrefixTable[exponent]
return value, prefix
}
// SI returns a string with default formatting.
//
// SI uses Ftoa to format float value, removing trailing zeros.
//
// See also: ComputeSI, ParseSI.
//
// e.g. SI(1000000, B) -> 1MB
// e.g. SI(2.2345e-12, "F") -> 2.2345pF
func SI(input float64, unit string) string {
value, prefix := ComputeSI(input)
return Ftoa(value) + prefix + unit
}
var errInvalid = errors.New("invalid input")
// ParseSI parses an SI string back into the number and unit.
//
// See also: SI, ComputeSI.
//
// e.g. ParseSI(2.2345pF) -> (2.2345e-12, "F", nil)
func ParseSI(input string) (float64, string, error) {
found := riParseRegex.FindStringSubmatch(input)
if len(found) != 4 {
return 0, "", errInvalid
}
mag := revSIPrefixTable[found[2]]
unit := found[3]
base, err := strconv.ParseFloat(found[1], 64)
return base * mag, unit, err
}
+98
View File
@@ -0,0 +1,98 @@
package humanize
import (
"math"
"testing"
)
func TestSI(t *testing.T) {
tests := []struct {
name string
num float64
formatted string
}{
{"e-24", 1e-24, "1yF"},
{"e-21", 1e-21, "1zF"},
{"e-18", 1e-18, "1aF"},
{"e-15", 1e-15, "1fF"},
{"e-12", 1e-12, "1pF"},
{"e-12", 2.2345e-12, "2.2345pF"},
{"e-12", 2.23e-12, "2.23pF"},
{"e-11", 2.23e-11, "22.3pF"},
{"e-10", 2.2e-10, "220pF"},
{"e-9", 2.2e-9, "2.2nF"},
{"e-8", 2.2e-8, "22nF"},
{"e-7", 2.2e-7, "220nF"},
{"e-6", 2.2e-6, "2.2µF"},
{"e-6", 1e-6, "1µF"},
{"e-5", 2.2e-5, "22µF"},
{"e-4", 2.2e-4, "220µF"},
{"e-3", 2.2e-3, "2.2mF"},
{"e-2", 2.2e-2, "22mF"},
{"e-1", 2.2e-1, "220mF"},
{"e+0", 2.2e-0, "2.2F"},
{"e+0", 2.2, "2.2F"},
{"e+1", 2.2e+1, "22F"},
{"0", 0, "0F"},
{"e+1", 22, "22F"},
{"e+2", 2.2e+2, "220F"},
{"e+2", 220, "220F"},
{"e+3", 2.2e+3, "2.2kF"},
{"e+3", 2200, "2.2kF"},
{"e+4", 2.2e+4, "22kF"},
{"e+4", 22000, "22kF"},
{"e+5", 2.2e+5, "220kF"},
{"e+6", 2.2e+6, "2.2MF"},
{"e+6", 1e+6, "1MF"},
{"e+7", 2.2e+7, "22MF"},
{"e+8", 2.2e+8, "220MF"},
{"e+9", 2.2e+9, "2.2GF"},
{"e+10", 2.2e+10, "22GF"},
{"e+11", 2.2e+11, "220GF"},
{"e+12", 2.2e+12, "2.2TF"},
{"e+15", 2.2e+15, "2.2PF"},
{"e+18", 2.2e+18, "2.2EF"},
{"e+21", 2.2e+21, "2.2ZF"},
{"e+24", 2.2e+24, "2.2YF"},
// special case
{"1F", 1000 * 1000, "1MF"},
{"1F", 1e6, "1MF"},
}
for _, test := range tests {
got := SI(test.num, "F")
if got != test.formatted {
t.Errorf("On %v (%v), got %v, wanted %v",
test.name, test.num, got, test.formatted)
}
gotf, gotu, err := ParseSI(test.formatted)
if err != nil {
t.Errorf("Error parsing %v (%v): %v", test.name, test.formatted, err)
continue
}
if math.Abs(1-(gotf/test.num)) > 0.01 {
t.Errorf("On %v (%v), got %v, wanted %v (±%v)",
test.name, test.formatted, gotf, test.num,
math.Abs(1-(gotf/test.num)))
}
if gotu != "F" {
t.Errorf("On %v (%v), expected unit F, got %v",
test.name, test.formatted, gotu)
}
}
// Parse error
gotf, gotu, err := ParseSI("x1.21JW") // 1.21 jigga whats
if err == nil {
t.Errorf("Expected error on x1.21JW, got %v %v", gotf, gotu)
}
}
func BenchmarkParseSI(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseSI("2.2346ZB")
}
}
+91
View File
@@ -0,0 +1,91 @@
package humanize
import (
"fmt"
"math"
"sort"
"time"
)
// Seconds-based time units
const (
Minute = 60
Hour = 60 * Minute
Day = 24 * Hour
Week = 7 * Day
Month = 30 * Day
Year = 12 * Month
LongTime = 37 * Year
)
// Time formats a time into a relative string.
//
// Time(someT) -> "3 weeks ago"
func Time(then time.Time) string {
return RelTime(then, time.Now(), "ago", "from now")
}
var magnitudes = []struct {
d int64
format string
divby int64
}{
{1, "now", 1},
{2, "1 second %s", 1},
{Minute, "%d seconds %s", 1},
{2 * Minute, "1 minute %s", 1},
{Hour, "%d minutes %s", Minute},
{2 * Hour, "1 hour %s", 1},
{Day, "%d hours %s", Hour},
{2 * Day, "1 day %s", 1},
{Week, "%d days %s", Day},
{2 * Week, "1 week %s", 1},
{Month, "%d weeks %s", Week},
{2 * Month, "1 month %s", 1},
{Year, "%d months %s", Month},
{18 * Month, "1 year %s", 1},
{2 * Year, "2 years %s", 1},
{LongTime, "%d years %s", Year},
{math.MaxInt64, "a long while %s", 1},
}
// RelTime formats a time into a relative string.
//
// It takes two times and two labels. In addition to the generic time
// delta string (e.g. 5 minutes), the labels are used applied so that
// the label corresponding to the smaller time is applied.
//
// RelTime(timeInPast, timeInFuture, "earlier", "later") -> "3 weeks earlier"
func RelTime(a, b time.Time, albl, blbl string) string {
lbl := albl
diff := b.Unix() - a.Unix()
after := a.After(b)
if after {
lbl = blbl
diff = a.Unix() - b.Unix()
}
n := sort.Search(len(magnitudes), func(i int) bool {
return magnitudes[i].d > diff
})
mag := magnitudes[n]
args := []interface{}{}
escaped := false
for _, ch := range mag.format {
if escaped {
switch ch {
case '%':
case 's':
args = append(args, lbl)
case 'd':
args = append(args, diff/mag.divby)
}
escaped = false
} else {
escaped = ch == '%'
}
}
return fmt.Sprintf(mag.format, args...)
}
+71
View File
@@ -0,0 +1,71 @@
package humanize
import (
"math"
"testing"
"time"
)
func TestPast(t *testing.T) {
now := time.Now().Unix()
testList{
{"now", Time(time.Unix(now, 0)), "now"},
{"1 second ago", Time(time.Unix(now-1, 0)), "1 second ago"},
{"12 seconds ago", Time(time.Unix(now-12, 0)), "12 seconds ago"},
{"30 seconds ago", Time(time.Unix(now-30, 0)), "30 seconds ago"},
{"45 seconds ago", Time(time.Unix(now-45, 0)), "45 seconds ago"},
{"1 minute ago", Time(time.Unix(now-63, 0)), "1 minute ago"},
{"15 minutes ago", Time(time.Unix(now-15*Minute, 0)), "15 minutes ago"},
{"1 hour ago", Time(time.Unix(now-63*Minute, 0)), "1 hour ago"},
{"2 hours ago", Time(time.Unix(now-2*Hour, 0)), "2 hours ago"},
{"21 hours ago", Time(time.Unix(now-21*Hour, 0)), "21 hours ago"},
{"1 day ago", Time(time.Unix(now-26*Hour, 0)), "1 day ago"},
{"2 days ago", Time(time.Unix(now-49*Hour, 0)), "2 days ago"},
{"3 days ago", Time(time.Unix(now-3*Day, 0)), "3 days ago"},
{"1 week ago (1)", Time(time.Unix(now-7*Day, 0)), "1 week ago"},
{"1 week ago (2)", Time(time.Unix(now-12*Day, 0)), "1 week ago"},
{"2 weeks ago", Time(time.Unix(now-15*Day, 0)), "2 weeks ago"},
{"1 month ago", Time(time.Unix(now-39*Day, 0)), "1 month ago"},
{"3 months ago", Time(time.Unix(now-99*Day, 0)), "3 months ago"},
{"1 year ago (1)", Time(time.Unix(now-365*Day, 0)), "1 year ago"},
{"1 year ago (1)", Time(time.Unix(now-400*Day, 0)), "1 year ago"},
{"2 years ago (1)", Time(time.Unix(now-548*Day, 0)), "2 years ago"},
{"2 years ago (2)", Time(time.Unix(now-725*Day, 0)), "2 years ago"},
{"2 years ago (3)", Time(time.Unix(now-800*Day, 0)), "2 years ago"},
{"3 years ago", Time(time.Unix(now-3*Year, 0)), "3 years ago"},
{"long ago", Time(time.Unix(now-LongTime, 0)), "a long while ago"},
}.validate(t)
}
func TestFuture(t *testing.T) {
now := time.Now().Unix()
testList{
{"now", Time(time.Unix(now, 0)), "now"},
{"1 second from now", Time(time.Unix(now+1, 0)), "1 second from now"},
{"12 seconds from now", Time(time.Unix(now+12, 0)), "12 seconds from now"},
{"30 seconds from now", Time(time.Unix(now+30, 0)), "30 seconds from now"},
{"45 seconds from now", Time(time.Unix(now+45, 0)), "45 seconds from now"},
{"15 minutes from now", Time(time.Unix(now+15*Minute, 0)), "15 minutes from now"},
{"2 hours from now", Time(time.Unix(now+2*Hour, 0)), "2 hours from now"},
{"21 hours from now", Time(time.Unix(now+21*Hour, 0)), "21 hours from now"},
{"1 day from now", Time(time.Unix(now+26*Hour, 0)), "1 day from now"},
{"2 days from now", Time(time.Unix(now+49*Hour, 0)), "2 days from now"},
{"3 days from now", Time(time.Unix(now+3*Day, 0)), "3 days from now"},
{"1 week from now (1)", Time(time.Unix(now+7*Day, 0)), "1 week from now"},
{"1 week from now (2)", Time(time.Unix(now+12*Day, 0)), "1 week from now"},
{"2 weeks from now", Time(time.Unix(now+15*Day, 0)), "2 weeks from now"},
{"1 month from now", Time(time.Unix(now+30*Day, 0)), "1 month from now"},
{"1 year from now", Time(time.Unix(now+365*Day, 0)), "1 year from now"},
{"2 years from now", Time(time.Unix(now+2*Year, 0)), "2 years from now"},
{"a while from now", Time(time.Unix(now+LongTime, 0)), "a long while from now"},
}.validate(t)
}
func TestRange(t *testing.T) {
start := time.Time{}
end := time.Unix(math.MaxInt64, math.MaxInt64)
x := RelTime(start, end, "ago", "from now")
if x != "a long while from now" {
t.Errorf("Expected a long while from now, got %q", x)
}
}
+7
View File
@@ -0,0 +1,7 @@
language: go
go:
- 1.0
- 1.1
- 1.2
- tip
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+7
View File
@@ -0,0 +1,7 @@
context
=======
[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context)
gorilla/context is a general purpose registry for global request variables.
Read the full documentation here: http://www.gorillatoolkit.org/pkg/context
+143
View File
@@ -0,0 +1,143 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package context
import (
"net/http"
"sync"
"time"
)
var (
mutex sync.RWMutex
data = make(map[*http.Request]map[interface{}]interface{})
datat = make(map[*http.Request]int64)
)
// Set stores a value for a given key in a given request.
func Set(r *http.Request, key, val interface{}) {
mutex.Lock()
if data[r] == nil {
data[r] = make(map[interface{}]interface{})
datat[r] = time.Now().Unix()
}
data[r][key] = val
mutex.Unlock()
}
// Get returns a value stored for a given key in a given request.
func Get(r *http.Request, key interface{}) interface{} {
mutex.RLock()
if ctx := data[r]; ctx != nil {
value := ctx[key]
mutex.RUnlock()
return value
}
mutex.RUnlock()
return nil
}
// GetOk returns stored value and presence state like multi-value return of map access.
func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
mutex.RLock()
if _, ok := data[r]; ok {
value, ok := data[r][key]
mutex.RUnlock()
return value, ok
}
mutex.RUnlock()
return nil, false
}
// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.
func GetAll(r *http.Request) map[interface{}]interface{} {
mutex.RLock()
if context, ok := data[r]; ok {
result := make(map[interface{}]interface{}, len(context))
for k, v := range context {
result[k] = v
}
mutex.RUnlock()
return result
}
mutex.RUnlock()
return nil
}
// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if
// the request was registered.
func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
mutex.RLock()
context, ok := data[r]
result := make(map[interface{}]interface{}, len(context))
for k, v := range context {
result[k] = v
}
mutex.RUnlock()
return result, ok
}
// Delete removes a value stored for a given key in a given request.
func Delete(r *http.Request, key interface{}) {
mutex.Lock()
if data[r] != nil {
delete(data[r], key)
}
mutex.Unlock()
}
// Clear removes all values stored for a given request.
//
// This is usually called by a handler wrapper to clean up request
// variables at the end of a request lifetime. See ClearHandler().
func Clear(r *http.Request) {
mutex.Lock()
clear(r)
mutex.Unlock()
}
// clear is Clear without the lock.
func clear(r *http.Request) {
delete(data, r)
delete(datat, r)
}
// Purge removes request data stored for longer than maxAge, in seconds.
// It returns the amount of requests removed.
//
// If maxAge <= 0, all request data is removed.
//
// This is only used for sanity check: in case context cleaning was not
// properly set some request data can be kept forever, consuming an increasing
// amount of memory. In case this is detected, Purge() must be called
// periodically until the problem is fixed.
func Purge(maxAge int) int {
mutex.Lock()
count := 0
if maxAge <= 0 {
count = len(data)
data = make(map[*http.Request]map[interface{}]interface{})
datat = make(map[*http.Request]int64)
} else {
min := time.Now().Unix() - int64(maxAge)
for r := range data {
if datat[r] < min {
clear(r)
count++
}
}
}
mutex.Unlock()
return count
}
// ClearHandler wraps an http.Handler and clears request values at the end
// of a request lifetime.
func ClearHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer Clear(r)
h.ServeHTTP(w, r)
})
}
+161
View File
@@ -0,0 +1,161 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package context
import (
"net/http"
"testing"
)
type keyType int
const (
key1 keyType = iota
key2
)
func TestContext(t *testing.T) {
assertEqual := func(val interface{}, exp interface{}) {
if val != exp {
t.Errorf("Expected %v, got %v.", exp, val)
}
}
r, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
emptyR, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
// Get()
assertEqual(Get(r, key1), nil)
// Set()
Set(r, key1, "1")
assertEqual(Get(r, key1), "1")
assertEqual(len(data[r]), 1)
Set(r, key2, "2")
assertEqual(Get(r, key2), "2")
assertEqual(len(data[r]), 2)
//GetOk
value, ok := GetOk(r, key1)
assertEqual(value, "1")
assertEqual(ok, true)
value, ok = GetOk(r, "not exists")
assertEqual(value, nil)
assertEqual(ok, false)
Set(r, "nil value", nil)
value, ok = GetOk(r, "nil value")
assertEqual(value, nil)
assertEqual(ok, true)
// GetAll()
values := GetAll(r)
assertEqual(len(values), 3)
// GetAll() for empty request
values = GetAll(emptyR)
if values != nil {
t.Error("GetAll didn't return nil value for invalid request")
}
// GetAllOk()
values, ok = GetAllOk(r)
assertEqual(len(values), 3)
assertEqual(ok, true)
// GetAllOk() for empty request
values, ok = GetAllOk(emptyR)
assertEqual(value, nil)
assertEqual(ok, false)
// Delete()
Delete(r, key1)
assertEqual(Get(r, key1), nil)
assertEqual(len(data[r]), 2)
Delete(r, key2)
assertEqual(Get(r, key2), nil)
assertEqual(len(data[r]), 1)
// Clear()
Clear(r)
assertEqual(len(data), 0)
}
func parallelReader(r *http.Request, key string, iterations int, wait, done chan struct{}) {
<-wait
for i := 0; i < iterations; i++ {
Get(r, key)
}
done <- struct{}{}
}
func parallelWriter(r *http.Request, key, value string, iterations int, wait, done chan struct{}) {
<-wait
for i := 0; i < iterations; i++ {
Set(r, key, value)
}
done <- struct{}{}
}
func benchmarkMutex(b *testing.B, numReaders, numWriters, iterations int) {
b.StopTimer()
r, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
done := make(chan struct{})
b.StartTimer()
for i := 0; i < b.N; i++ {
wait := make(chan struct{})
for i := 0; i < numReaders; i++ {
go parallelReader(r, "test", iterations, wait, done)
}
for i := 0; i < numWriters; i++ {
go parallelWriter(r, "test", "123", iterations, wait, done)
}
close(wait)
for i := 0; i < numReaders+numWriters; i++ {
<-done
}
}
}
func BenchmarkMutexSameReadWrite1(b *testing.B) {
benchmarkMutex(b, 1, 1, 32)
}
func BenchmarkMutexSameReadWrite2(b *testing.B) {
benchmarkMutex(b, 2, 2, 32)
}
func BenchmarkMutexSameReadWrite4(b *testing.B) {
benchmarkMutex(b, 4, 4, 32)
}
func BenchmarkMutex1(b *testing.B) {
benchmarkMutex(b, 2, 8, 32)
}
func BenchmarkMutex2(b *testing.B) {
benchmarkMutex(b, 16, 4, 64)
}
func BenchmarkMutex3(b *testing.B) {
benchmarkMutex(b, 1, 2, 128)
}
func BenchmarkMutex4(b *testing.B) {
benchmarkMutex(b, 128, 32, 256)
}
func BenchmarkMutex5(b *testing.B) {
benchmarkMutex(b, 1024, 2048, 64)
}
func BenchmarkMutex6(b *testing.B) {
benchmarkMutex(b, 2048, 1024, 512)
}
+82
View File
@@ -0,0 +1,82 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package context stores values shared during a request lifetime.
For example, a router can set variables extracted from the URL and later
application handlers can access those values, or it can be used to store
sessions values to be saved at the end of a request. There are several
others common uses.
The idea was posted by Brad Fitzpatrick to the go-nuts mailing list:
http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53
Here's the basic usage: first define the keys that you will need. The key
type is interface{} so a key can be of any type that supports equality.
Here we define a key using a custom int type to avoid name collisions:
package foo
import (
"github.com/gorilla/context"
)
type key int
const MyKey key = 0
Then set a variable. Variables are bound to an http.Request object, so you
need a request instance to set a value:
context.Set(r, MyKey, "bar")
The application can later access the variable using the same key you provided:
func MyHandler(w http.ResponseWriter, r *http.Request) {
// val is "bar".
val := context.Get(r, foo.MyKey)
// returns ("bar", true)
val, ok := context.GetOk(r, foo.MyKey)
// ...
}
And that's all about the basic usage. We discuss some other ideas below.
Any type can be stored in the context. To enforce a given type, make the key
private and wrap Get() and Set() to accept and return values of a specific
type:
type key int
const mykey key = 0
// GetMyKey returns a value for this package from the request values.
func GetMyKey(r *http.Request) SomeType {
if rv := context.Get(r, mykey); rv != nil {
return rv.(SomeType)
}
return nil
}
// SetMyKey sets a value for this package in the request values.
func SetMyKey(r *http.Request, val SomeType) {
context.Set(r, mykey, val)
}
Variables must be cleared at the end of a request, to remove all values
that were stored. This can be done in an http.Handler, after a request was
served. Just call Clear() passing the request:
context.Clear(r)
...or use ClearHandler(), which conveniently wraps an http.Handler to clear
variables at the end of a request lifetime.
The Routers from the packages gorilla/mux and gorilla/pat call Clear()
so if you are using either of them you don't need to clear the context manually.
*/
package context
+7
View File
@@ -0,0 +1,7 @@
language: go
go:
- 1.0
- 1.1
- 1.2
- tip
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+7
View File
@@ -0,0 +1,7 @@
mux
===
[![Build Status](https://travis-ci.org/gorilla/mux.png?branch=master)](https://travis-ci.org/gorilla/mux)
gorilla/mux is a powerful URL router and dispatcher.
Read the full documentation here: http://www.gorillatoolkit.org/pkg/mux
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mux
import (
"net/http"
"testing"
)
func BenchmarkMux(b *testing.B) {
router := new(Router)
handler := func(w http.ResponseWriter, r *http.Request) {}
router.HandleFunc("/v1/{v1}", handler)
request, _ := http.NewRequest("GET", "/v1/anything", nil)
for i := 0; i < b.N; i++ {
router.ServeHTTP(nil, request)
}
}
+199
View File
@@ -0,0 +1,199 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package gorilla/mux implements a request router and dispatcher.
The name mux stands for "HTTP request multiplexer". Like the standard
http.ServeMux, mux.Router matches incoming requests against a list of
registered routes and calls a handler for the route that matches the URL
or other conditions. The main features are:
* Requests can be matched based on URL host, path, path prefix, schemes,
header and query values, HTTP methods or using custom matchers.
* URL hosts and paths can have variables with an optional regular
expression.
* Registered URLs can be built, or "reversed", which helps maintaining
references to resources.
* Routes can be used as subrouters: nested routes are only tested if the
parent route matches. This is useful to define groups of routes that
share common conditions like a host, a path prefix or other repeated
attributes. As a bonus, this optimizes request matching.
* It implements the http.Handler interface so it is compatible with the
standard http.ServeMux.
Let's start registering a couple of URL paths and handlers:
func main() {
r := mux.NewRouter()
r.HandleFunc("/", HomeHandler)
r.HandleFunc("/products", ProductsHandler)
r.HandleFunc("/articles", ArticlesHandler)
http.Handle("/", r)
}
Here we register three routes mapping URL paths to handlers. This is
equivalent to how http.HandleFunc() works: if an incoming request URL matches
one of the paths, the corresponding handler is called passing
(http.ResponseWriter, *http.Request) as parameters.
Paths can have variables. They are defined using the format {name} or
{name:pattern}. If a regular expression pattern is not defined, the matched
variable will be anything until the next slash. For example:
r := mux.NewRouter()
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
The names are used to create a map of route variables which can be retrieved
calling mux.Vars():
vars := mux.Vars(request)
category := vars["category"]
And this is all you need to know about the basic usage. More advanced options
are explained below.
Routes can also be restricted to a domain or subdomain. Just define a host
pattern to be matched. They can also have variables:
r := mux.NewRouter()
// Only matches if domain is "www.domain.com".
r.Host("www.domain.com")
// Matches a dynamic subdomain.
r.Host("{subdomain:[a-z]+}.domain.com")
There are several other matchers that can be added. To match path prefixes:
r.PathPrefix("/products/")
...or HTTP methods:
r.Methods("GET", "POST")
...or URL schemes:
r.Schemes("https")
...or header values:
r.Headers("X-Requested-With", "XMLHttpRequest")
...or query values:
r.Queries("key", "value")
...or to use a custom matcher function:
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
return r.ProtoMajor == 0
})
...and finally, it is possible to combine several matchers in a single route:
r.HandleFunc("/products", ProductsHandler).
Host("www.domain.com").
Methods("GET").
Schemes("http")
Setting the same matching conditions again and again can be boring, so we have
a way to group several routes that share the same requirements.
We call it "subrouting".
For example, let's say we have several URLs that should only match when the
host is "www.domain.com". Create a route for that host and get a "subrouter"
from it:
r := mux.NewRouter()
s := r.Host("www.domain.com").Subrouter()
Then register routes in the subrouter:
s.HandleFunc("/products/", ProductsHandler)
s.HandleFunc("/products/{key}", ProductHandler)
s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
The three URL paths we registered above will only be tested if the domain is
"www.domain.com", because the subrouter is tested first. This is not
only convenient, but also optimizes request matching. You can create
subrouters combining any attribute matchers accepted by a route.
Subrouters can be used to create domain or path "namespaces": you define
subrouters in a central place and then parts of the app can register its
paths relatively to a given subrouter.
There's one more thing about subroutes. When a subrouter has a path prefix,
the inner routes use it as base for their paths:
r := mux.NewRouter()
s := r.PathPrefix("/products").Subrouter()
// "/products/"
s.HandleFunc("/", ProductsHandler)
// "/products/{key}/"
s.HandleFunc("/{key}/", ProductHandler)
// "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler)
Now let's see how to build registered URLs.
Routes can be named. All routes that define a name can have their URLs built,
or "reversed". We define a name calling Name() on a route. For example:
r := mux.NewRouter()
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
Name("article")
To build a URL, get the route and call the URL() method, passing a sequence of
key/value pairs for the route variables. For the previous route, we would do:
url, err := r.Get("article").URL("category", "technology", "id", "42")
...and the result will be a url.URL with the following path:
"/articles/technology/42"
This also works for host variables:
r := mux.NewRouter()
r.Host("{subdomain}.domain.com").
Path("/articles/{category}/{id:[0-9]+}").
HandlerFunc(ArticleHandler).
Name("article")
// url.String() will be "http://news.domain.com/articles/technology/42"
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
"id", "42")
All variables defined in the route are required, and their values must
conform to the corresponding patterns. These requirements guarantee that a
generated URL will always match a registered route -- the only exception is
for explicitly defined "build-only" routes which never match.
There's also a way to build only the URL host or path for a route:
use the methods URLHost() or URLPath() instead. For the previous route,
we would do:
// "http://news.domain.com/"
host, err := r.Get("article").URLHost("subdomain", "news")
// "/articles/technology/42"
path, err := r.Get("article").URLPath("category", "technology", "id", "42")
And if you use subrouters, host and path defined separately can be built
as well:
r := mux.NewRouter()
s := r.Host("{subdomain}.domain.com").Subrouter()
s.Path("/articles/{category}/{id:[0-9]+}").
HandlerFunc(ArticleHandler).
Name("article")
// "http://news.domain.com/articles/technology/42"
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
"id", "42")
*/
package mux
+353
View File
@@ -0,0 +1,353 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mux
import (
"fmt"
"net/http"
"path"
"github.com/gorilla/context"
)
// NewRouter returns a new router instance.
func NewRouter() *Router {
return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}
// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
// var router = mux.NewRouter()
//
// func main() {
// http.Handle("/", router)
// }
//
// Or, for Google App Engine, register it in a init() function:
//
// func init() {
// http.Handle("/", router)
// }
//
// This will send all incoming requests to the router.
type Router struct {
// Configurable Handler to be used when no route matches.
NotFoundHandler http.Handler
// Parent route, if this is a subrouter.
parent parentRoute
// Routes to be matched, in order.
routes []*Route
// Routes by name for URL building.
namedRoutes map[string]*Route
// See Router.StrictSlash(). This defines the flag for new routes.
strictSlash bool
// If true, do not clear the request context after handling the request
KeepContext bool
}
// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
for _, route := range r.routes {
if route.Match(req, match) {
return true
}
}
return false
}
// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Clean path to canonical form and redirect.
if p := cleanPath(req.URL.Path); p != req.URL.Path {
// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
// http://code.google.com/p/go/issues/detail?id=5252
url := *req.URL
url.Path = p
p = url.String()
w.Header().Set("Location", p)
w.WriteHeader(http.StatusMovedPermanently)
return
}
var match RouteMatch
var handler http.Handler
if r.Match(req, &match) {
handler = match.Handler
setVars(req, match.Vars)
setCurrentRoute(req, match.Route)
}
if handler == nil {
handler = r.NotFoundHandler
if handler == nil {
handler = http.NotFoundHandler()
}
}
if !r.KeepContext {
defer context.Clear(req)
}
handler.ServeHTTP(w, req)
}
// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
return r.getNamedRoutes()[name]
}
// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
return r.getNamedRoutes()[name]
}
// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
r.strictSlash = value
return r
}
// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------
// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
if r.namedRoutes == nil {
if r.parent != nil {
r.namedRoutes = r.parent.getNamedRoutes()
} else {
r.namedRoutes = make(map[string]*Route)
}
}
return r.namedRoutes
}
// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
if r.parent != nil {
return r.parent.getRegexpGroup()
}
return nil
}
// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------
// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
route := &Route{parent: r, strictSlash: r.strictSlash}
r.routes = append(r.routes, route)
return route
}
// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
return r.NewRoute().Path(path).Handler(handler)
}
// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
*http.Request)) *Route {
return r.NewRoute().Path(path).HandlerFunc(f)
}
// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
return r.NewRoute().Headers(pairs...)
}
// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
return r.NewRoute().Host(tpl)
}
// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
return r.NewRoute().MatcherFunc(f)
}
// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
return r.NewRoute().Methods(methods...)
}
// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
return r.NewRoute().Path(tpl)
}
// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
return r.NewRoute().PathPrefix(tpl)
}
// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
return r.NewRoute().Queries(pairs...)
}
// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
return r.NewRoute().Schemes(schemes...)
}
// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------
// RouteMatch stores information about a matched route.
type RouteMatch struct {
Route *Route
Handler http.Handler
Vars map[string]string
}
type contextKey int
const (
varsKey contextKey = iota
routeKey
)
// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
if rv := context.Get(r, varsKey); rv != nil {
return rv.(map[string]string)
}
return nil
}
// CurrentRoute returns the matched route for the current request, if any.
func CurrentRoute(r *http.Request) *Route {
if rv := context.Get(r, routeKey); rv != nil {
return rv.(*Route)
}
return nil
}
func setVars(r *http.Request, val interface{}) {
context.Set(r, varsKey, val)
}
func setCurrentRoute(r *http.Request, val interface{}) {
context.Set(r, routeKey, val)
}
// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------
// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
if p == "" {
return "/"
}
if p[0] != '/' {
p = "/" + p
}
np := path.Clean(p)
// path.Clean removes trailing slash except for root;
// put the trailing slash back if necessary.
if p[len(p)-1] == '/' && np != "/" {
np += "/"
}
return np
}
// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
for _, v1 := range s1 {
for _, v2 := range s2 {
if v1 == v2 {
return fmt.Errorf("mux: duplicated route variable %q", v2)
}
}
}
return nil
}
// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairs(pairs ...string) (map[string]string, error) {
length := len(pairs)
if length%2 != 0 {
return nil, fmt.Errorf(
"mux: number of parameters must be multiple of 2, got %v", pairs)
}
m := make(map[string]string, length/2)
for i := 0; i < length; i += 2 {
m[pairs[i]] = pairs[i+1]
}
return m, nil
}
// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
for _, v := range arr {
if v == value {
return true
}
}
return false
}
// matchMap returns true if the given key/value pairs exist in a given map.
func matchMap(toCheck map[string]string, toMatch map[string][]string,
canonicalKey bool) bool {
for k, v := range toCheck {
// Check if key exists.
if canonicalKey {
k = http.CanonicalHeaderKey(k)
}
if values := toMatch[k]; values == nil {
return false
} else if v != "" {
// If value was defined as an empty string we only check that the
// key exists. Otherwise we also check for equality.
valueExists := false
for _, value := range values {
if v == value {
valueExists = true
break
}
}
if !valueExists {
return false
}
}
}
return true
}
+943
View File
@@ -0,0 +1,943 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mux
import (
"fmt"
"net/http"
"testing"
"github.com/gorilla/context"
)
type routeTest struct {
title string // title of the test
route *Route // the route being tested
request *http.Request // a request to test the route
vars map[string]string // the expected vars of the match
host string // the expected host of the match
path string // the expected path of the match
shouldMatch bool // whether the request is expected to match the route at all
shouldRedirect bool // whether the request should result in a redirect
}
func TestHost(t *testing.T) {
// newRequestHost a new request with a method, url, and host header
newRequestHost := func(method, url, host string) *http.Request {
req, err := http.NewRequest(method, url, nil)
if err != nil {
panic(err)
}
req.Host = host
return req
}
tests := []routeTest{
{
title: "Host route match",
route: new(Route).Host("aaa.bbb.ccc"),
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
vars: map[string]string{},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: true,
},
{
title: "Host route, wrong host in request URL",
route: new(Route).Host("aaa.bbb.ccc"),
request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
vars: map[string]string{},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: false,
},
{
title: "Host route with port, match",
route: new(Route).Host("aaa.bbb.ccc:1234"),
request: newRequest("GET", "http://aaa.bbb.ccc:1234/111/222/333"),
vars: map[string]string{},
host: "aaa.bbb.ccc:1234",
path: "",
shouldMatch: true,
},
{
title: "Host route with port, wrong port in request URL",
route: new(Route).Host("aaa.bbb.ccc:1234"),
request: newRequest("GET", "http://aaa.bbb.ccc:9999/111/222/333"),
vars: map[string]string{},
host: "aaa.bbb.ccc:1234",
path: "",
shouldMatch: false,
},
{
title: "Host route, match with host in request header",
route: new(Route).Host("aaa.bbb.ccc"),
request: newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc"),
vars: map[string]string{},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: true,
},
{
title: "Host route, wrong host in request header",
route: new(Route).Host("aaa.bbb.ccc"),
request: newRequestHost("GET", "/111/222/333", "aaa.222.ccc"),
vars: map[string]string{},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: false,
},
// BUG {new(Route).Host("aaa.bbb.ccc:1234"), newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc:1234"), map[string]string{}, "aaa.bbb.ccc:1234", "", true},
{
title: "Host route with port, wrong host in request header",
route: new(Route).Host("aaa.bbb.ccc:1234"),
request: newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc:9999"),
vars: map[string]string{},
host: "aaa.bbb.ccc:1234",
path: "",
shouldMatch: false,
},
{
title: "Host route with pattern, match",
route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"),
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
vars: map[string]string{"v1": "bbb"},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: true,
},
{
title: "Host route with pattern, wrong host in request URL",
route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"),
request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
vars: map[string]string{"v1": "bbb"},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: false,
},
{
title: "Host route with multiple patterns, match",
route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}"),
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: true,
},
{
title: "Host route with multiple patterns, wrong host in request URL",
route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}"),
request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"},
host: "aaa.bbb.ccc",
path: "",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestPath(t *testing.T) {
tests := []routeTest{
{
title: "Path route, match",
route: new(Route).Path("/111/222/333"),
request: newRequest("GET", "http://localhost/111/222/333"),
vars: map[string]string{},
host: "",
path: "/111/222/333",
shouldMatch: true,
},
{
title: "Path route, match with trailing slash in request and path",
route: new(Route).Path("/111/"),
request: newRequest("GET", "http://localhost/111/"),
vars: map[string]string{},
host: "",
path: "/111/",
shouldMatch: true,
},
{
title: "Path route, do not match with trailing slash in path",
route: new(Route).Path("/111/"),
request: newRequest("GET", "http://localhost/111"),
vars: map[string]string{},
host: "",
path: "/111",
shouldMatch: false,
},
{
title: "Path route, do not match with trailing slash in request",
route: new(Route).Path("/111"),
request: newRequest("GET", "http://localhost/111/"),
vars: map[string]string{},
host: "",
path: "/111/",
shouldMatch: false,
},
{
title: "Path route, wrong path in request in request URL",
route: new(Route).Path("/111/222/333"),
request: newRequest("GET", "http://localhost/1/2/3"),
vars: map[string]string{},
host: "",
path: "/111/222/333",
shouldMatch: false,
},
{
title: "Path route with pattern, match",
route: new(Route).Path("/111/{v1:[0-9]{3}}/333"),
request: newRequest("GET", "http://localhost/111/222/333"),
vars: map[string]string{"v1": "222"},
host: "",
path: "/111/222/333",
shouldMatch: true,
},
{
title: "Path route with pattern, URL in request does not match",
route: new(Route).Path("/111/{v1:[0-9]{3}}/333"),
request: newRequest("GET", "http://localhost/111/aaa/333"),
vars: map[string]string{"v1": "222"},
host: "",
path: "/111/222/333",
shouldMatch: false,
},
{
title: "Path route with multiple patterns, match",
route: new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}"),
request: newRequest("GET", "http://localhost/111/222/333"),
vars: map[string]string{"v1": "111", "v2": "222", "v3": "333"},
host: "",
path: "/111/222/333",
shouldMatch: true,
},
{
title: "Path route with multiple patterns, URL in request does not match",
route: new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}"),
request: newRequest("GET", "http://localhost/111/aaa/333"),
vars: map[string]string{"v1": "111", "v2": "222", "v3": "333"},
host: "",
path: "/111/222/333",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestPathPrefix(t *testing.T) {
tests := []routeTest{
{
title: "PathPrefix route, match",
route: new(Route).PathPrefix("/111"),
request: newRequest("GET", "http://localhost/111/222/333"),
vars: map[string]string{},
host: "",
path: "/111",
shouldMatch: true,
},
{
title: "PathPrefix route, match substring",
route: new(Route).PathPrefix("/1"),
request: newRequest("GET", "http://localhost/111/222/333"),
vars: map[string]string{},
host: "",
path: "/1",
shouldMatch: true,
},
{
title: "PathPrefix route, URL prefix in request does not match",
route: new(Route).PathPrefix("/111"),
request: newRequest("GET", "http://localhost/1/2/3"),
vars: map[string]string{},
host: "",
path: "/111",
shouldMatch: false,
},
{
title: "PathPrefix route with pattern, match",
route: new(Route).PathPrefix("/111/{v1:[0-9]{3}}"),
request: newRequest("GET", "http://localhost/111/222/333"),
vars: map[string]string{"v1": "222"},
host: "",
path: "/111/222",
shouldMatch: true,
},
{
title: "PathPrefix route with pattern, URL prefix in request does not match",
route: new(Route).PathPrefix("/111/{v1:[0-9]{3}}"),
request: newRequest("GET", "http://localhost/111/aaa/333"),
vars: map[string]string{"v1": "222"},
host: "",
path: "/111/222",
shouldMatch: false,
},
{
title: "PathPrefix route with multiple patterns, match",
route: new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}"),
request: newRequest("GET", "http://localhost/111/222/333"),
vars: map[string]string{"v1": "111", "v2": "222"},
host: "",
path: "/111/222",
shouldMatch: true,
},
{
title: "PathPrefix route with multiple patterns, URL prefix in request does not match",
route: new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}"),
request: newRequest("GET", "http://localhost/111/aaa/333"),
vars: map[string]string{"v1": "111", "v2": "222"},
host: "",
path: "/111/222",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestHostPath(t *testing.T) {
tests := []routeTest{
{
title: "Host and Path route, match",
route: new(Route).Host("aaa.bbb.ccc").Path("/111/222/333"),
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Host and Path route, wrong host in request URL",
route: new(Route).Host("aaa.bbb.ccc").Path("/111/222/333"),
request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: false,
},
{
title: "Host and Path route with pattern, match",
route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333"),
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
vars: map[string]string{"v1": "bbb", "v2": "222"},
host: "aaa.bbb.ccc",
path: "/111/222/333",
shouldMatch: true,
},
{
title: "Host and Path route with pattern, URL in request does not match",
route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333"),
request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
vars: map[string]string{"v1": "bbb", "v2": "222"},
host: "aaa.bbb.ccc",
path: "/111/222/333",
shouldMatch: false,
},
{
title: "Host and Path route with multiple patterns, match",
route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}"),
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"},
host: "aaa.bbb.ccc",
path: "/111/222/333",
shouldMatch: true,
},
{
title: "Host and Path route with multiple patterns, URL in request does not match",
route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}"),
request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"},
host: "aaa.bbb.ccc",
path: "/111/222/333",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestHeaders(t *testing.T) {
// newRequestHeaders creates a new request with a method, url, and headers
newRequestHeaders := func(method, url string, headers map[string]string) *http.Request {
req, err := http.NewRequest(method, url, nil)
if err != nil {
panic(err)
}
for k, v := range headers {
req.Header.Add(k, v)
}
return req
}
tests := []routeTest{
{
title: "Headers route, match",
route: new(Route).Headers("foo", "bar", "baz", "ding"),
request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar", "baz": "ding"}),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Headers route, bad header values",
route: new(Route).Headers("foo", "bar", "baz", "ding"),
request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar", "baz": "dong"}),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestMethods(t *testing.T) {
tests := []routeTest{
{
title: "Methods route, match GET",
route: new(Route).Methods("GET", "POST"),
request: newRequest("GET", "http://localhost"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Methods route, match POST",
route: new(Route).Methods("GET", "POST"),
request: newRequest("POST", "http://localhost"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Methods route, bad method",
route: new(Route).Methods("GET", "POST"),
request: newRequest("PUT", "http://localhost"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestQueries(t *testing.T) {
tests := []routeTest{
{
title: "Queries route, match",
route: new(Route).Queries("foo", "bar", "baz", "ding"),
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Queries route, match with a query string",
route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Queries route, match with a query string out of order",
route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
request: newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Queries route, bad query",
route: new(Route).Queries("foo", "bar", "baz", "ding"),
request: newRequest("GET", "http://localhost?foo=bar&baz=dong"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: false,
},
{
title: "Queries route with pattern, match",
route: new(Route).Queries("foo", "{v1}"),
request: newRequest("GET", "http://localhost?foo=bar"),
vars: map[string]string{"v1": "bar"},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Queries route with multiple patterns, match",
route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
vars: map[string]string{"v1": "bar", "v2": "ding"},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Queries route with regexp pattern, match",
route: new(Route).Queries("foo", "{v1:[0-9]+}"),
request: newRequest("GET", "http://localhost?foo=10"),
vars: map[string]string{"v1": "10"},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Queries route with regexp pattern, regexp does not match",
route: new(Route).Queries("foo", "{v1:[0-9]+}"),
request: newRequest("GET", "http://localhost?foo=a"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestSchemes(t *testing.T) {
tests := []routeTest{
// Schemes
{
title: "Schemes route, match https",
route: new(Route).Schemes("https", "ftp"),
request: newRequest("GET", "https://localhost"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Schemes route, match ftp",
route: new(Route).Schemes("https", "ftp"),
request: newRequest("GET", "ftp://localhost"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "Schemes route, bad scheme",
route: new(Route).Schemes("https", "ftp"),
request: newRequest("GET", "http://localhost"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestMatcherFunc(t *testing.T) {
m := func(r *http.Request, m *RouteMatch) bool {
if r.URL.Host == "aaa.bbb.ccc" {
return true
}
return false
}
tests := []routeTest{
{
title: "MatchFunc route, match",
route: new(Route).MatcherFunc(m),
request: newRequest("GET", "http://aaa.bbb.ccc"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: true,
},
{
title: "MatchFunc route, non-match",
route: new(Route).MatcherFunc(m),
request: newRequest("GET", "http://aaa.222.ccc"),
vars: map[string]string{},
host: "",
path: "",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestSubRouter(t *testing.T) {
subrouter1 := new(Route).Host("{v1:[a-z]+}.google.com").Subrouter()
subrouter2 := new(Route).PathPrefix("/foo/{v1}").Subrouter()
tests := []routeTest{
{
route: subrouter1.Path("/{v2:[a-z]+}"),
request: newRequest("GET", "http://aaa.google.com/bbb"),
vars: map[string]string{"v1": "aaa", "v2": "bbb"},
host: "aaa.google.com",
path: "/bbb",
shouldMatch: true,
},
{
route: subrouter1.Path("/{v2:[a-z]+}"),
request: newRequest("GET", "http://111.google.com/111"),
vars: map[string]string{"v1": "aaa", "v2": "bbb"},
host: "aaa.google.com",
path: "/bbb",
shouldMatch: false,
},
{
route: subrouter2.Path("/baz/{v2}"),
request: newRequest("GET", "http://localhost/foo/bar/baz/ding"),
vars: map[string]string{"v1": "bar", "v2": "ding"},
host: "",
path: "/foo/bar/baz/ding",
shouldMatch: true,
},
{
route: subrouter2.Path("/baz/{v2}"),
request: newRequest("GET", "http://localhost/foo/bar"),
vars: map[string]string{"v1": "bar", "v2": "ding"},
host: "",
path: "/foo/bar/baz/ding",
shouldMatch: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
func TestNamedRoutes(t *testing.T) {
r1 := NewRouter()
r1.NewRoute().Name("a")
r1.NewRoute().Name("b")
r1.NewRoute().Name("c")
r2 := r1.NewRoute().Subrouter()
r2.NewRoute().Name("d")
r2.NewRoute().Name("e")
r2.NewRoute().Name("f")
r3 := r2.NewRoute().Subrouter()
r3.NewRoute().Name("g")
r3.NewRoute().Name("h")
r3.NewRoute().Name("i")
if r1.namedRoutes == nil || len(r1.namedRoutes) != 9 {
t.Errorf("Expected 9 named routes, got %v", r1.namedRoutes)
} else if r1.Get("i") == nil {
t.Errorf("Subroute name not registered")
}
}
func TestStrictSlash(t *testing.T) {
r := NewRouter()
r.StrictSlash(true)
tests := []routeTest{
{
title: "Redirect path without slash",
route: r.NewRoute().Path("/111/"),
request: newRequest("GET", "http://localhost/111"),
vars: map[string]string{},
host: "",
path: "/111/",
shouldMatch: true,
shouldRedirect: true,
},
{
title: "Do not redirect path with slash",
route: r.NewRoute().Path("/111/"),
request: newRequest("GET", "http://localhost/111/"),
vars: map[string]string{},
host: "",
path: "/111/",
shouldMatch: true,
shouldRedirect: false,
},
{
title: "Redirect path with slash",
route: r.NewRoute().Path("/111"),
request: newRequest("GET", "http://localhost/111/"),
vars: map[string]string{},
host: "",
path: "/111",
shouldMatch: true,
shouldRedirect: true,
},
{
title: "Do not redirect path without slash",
route: r.NewRoute().Path("/111"),
request: newRequest("GET", "http://localhost/111"),
vars: map[string]string{},
host: "",
path: "/111",
shouldMatch: true,
shouldRedirect: false,
},
{
title: "Propagate StrictSlash to subrouters",
route: r.NewRoute().PathPrefix("/static/").Subrouter().Path("/images/"),
request: newRequest("GET", "http://localhost/static/images"),
vars: map[string]string{},
host: "",
path: "/static/images/",
shouldMatch: true,
shouldRedirect: true,
},
{
title: "Ignore StrictSlash for path prefix",
route: r.NewRoute().PathPrefix("/static/"),
request: newRequest("GET", "http://localhost/static/logo.png"),
vars: map[string]string{},
host: "",
path: "/static/",
shouldMatch: true,
shouldRedirect: false,
},
}
for _, test := range tests {
testRoute(t, test)
}
}
// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------
func getRouteTemplate(route *Route) string {
host, path := "none", "none"
if route.regexp != nil {
if route.regexp.host != nil {
host = route.regexp.host.template
}
if route.regexp.path != nil {
path = route.regexp.path.template
}
}
return fmt.Sprintf("Host: %v, Path: %v", host, path)
}
func testRoute(t *testing.T, test routeTest) {
request := test.request
route := test.route
vars := test.vars
shouldMatch := test.shouldMatch
host := test.host
path := test.path
url := test.host + test.path
shouldRedirect := test.shouldRedirect
var match RouteMatch
ok := route.Match(request, &match)
if ok != shouldMatch {
msg := "Should match"
if !shouldMatch {
msg = "Should not match"
}
t.Errorf("(%v) %v:\nRoute: %#v\nRequest: %#v\nVars: %v\n", test.title, msg, route, request, vars)
return
}
if shouldMatch {
if test.vars != nil && !stringMapEqual(test.vars, match.Vars) {
t.Errorf("(%v) Vars not equal: expected %v, got %v", test.title, vars, match.Vars)
return
}
if host != "" {
u, _ := test.route.URLHost(mapToPairs(match.Vars)...)
if host != u.Host {
t.Errorf("(%v) URLHost not equal: expected %v, got %v -- %v", test.title, host, u.Host, getRouteTemplate(route))
return
}
}
if path != "" {
u, _ := route.URLPath(mapToPairs(match.Vars)...)
if path != u.Path {
t.Errorf("(%v) URLPath not equal: expected %v, got %v -- %v", test.title, path, u.Path, getRouteTemplate(route))
return
}
}
if url != "" {
u, _ := route.URL(mapToPairs(match.Vars)...)
if url != u.Host+u.Path {
t.Errorf("(%v) URL not equal: expected %v, got %v -- %v", test.title, url, u.Host+u.Path, getRouteTemplate(route))
return
}
}
if shouldRedirect && match.Handler == nil {
t.Errorf("(%v) Did not redirect", test.title)
return
}
if !shouldRedirect && match.Handler != nil {
t.Errorf("(%v) Unexpected redirect", test.title)
return
}
}
}
// Tests that the context is cleared or not cleared properly depending on
// the configuration of the router
func TestKeepContext(t *testing.T) {
func1 := func(w http.ResponseWriter, r *http.Request) {}
r := NewRouter()
r.HandleFunc("/", func1).Name("func1")
req, _ := http.NewRequest("GET", "http://localhost/", nil)
context.Set(req, "t", 1)
res := new(http.ResponseWriter)
r.ServeHTTP(*res, req)
if _, ok := context.GetOk(req, "t"); ok {
t.Error("Context should have been cleared at end of request")
}
r.KeepContext = true
req, _ = http.NewRequest("GET", "http://localhost/", nil)
context.Set(req, "t", 1)
r.ServeHTTP(*res, req)
if _, ok := context.GetOk(req, "t"); !ok {
t.Error("Context should NOT have been cleared at end of request")
}
}
type TestA301ResponseWriter struct {
hh http.Header
status int
}
func (ho TestA301ResponseWriter) Header() http.Header {
return http.Header(ho.hh)
}
func (ho TestA301ResponseWriter) Write(b []byte) (int, error) {
return 0, nil
}
func (ho TestA301ResponseWriter) WriteHeader(code int) {
ho.status = code
}
func Test301Redirect(t *testing.T) {
m := make(http.Header)
func1 := func(w http.ResponseWriter, r *http.Request) {}
func2 := func(w http.ResponseWriter, r *http.Request) {}
r := NewRouter()
r.HandleFunc("/api/", func2).Name("func2")
r.HandleFunc("/", func1).Name("func1")
req, _ := http.NewRequest("GET", "http://localhost//api/?abc=def", nil)
res := TestA301ResponseWriter{
hh: m,
status: 0,
}
r.ServeHTTP(&res, req)
if "http://localhost/api/?abc=def" != res.hh["Location"][0] {
t.Errorf("Should have complete URL with query string")
}
}
// https://plus.google.com/101022900381697718949/posts/eWy6DjFJ6uW
func TestSubrouterHeader(t *testing.T) {
expected := "func1 response"
func1 := func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, expected)
}
func2 := func(http.ResponseWriter, *http.Request) {}
r := NewRouter()
s := r.Headers("SomeSpecialHeader", "").Subrouter()
s.HandleFunc("/", func1).Name("func1")
r.HandleFunc("/", func2).Name("func2")
req, _ := http.NewRequest("GET", "http://localhost/", nil)
req.Header.Add("SomeSpecialHeader", "foo")
match := new(RouteMatch)
matched := r.Match(req, match)
if !matched {
t.Errorf("Should match request")
}
if match.Route.GetName() != "func1" {
t.Errorf("Expecting func1 handler, got %s", match.Route.GetName())
}
resp := NewRecorder()
match.Handler.ServeHTTP(resp, req)
if resp.Body.String() != expected {
t.Errorf("Expecting %q", expected)
}
}
// mapToPairs converts a string map to a slice of string pairs
func mapToPairs(m map[string]string) []string {
var i int
p := make([]string, len(m)*2)
for k, v := range m {
p[i] = k
p[i+1] = v
i += 2
}
return p
}
// stringMapEqual checks the equality of two string maps
func stringMapEqual(m1, m2 map[string]string) bool {
nil1 := m1 == nil
nil2 := m2 == nil
if nil1 != nil2 || len(m1) != len(m2) {
return false
}
for k, v := range m1 {
if v != m2[k] {
return false
}
}
return true
}
// newRequest is a helper function to create a new request with a method and url
func newRequest(method, url string) *http.Request {
req, err := http.NewRequest(method, url, nil)
if err != nil {
panic(err)
}
return req
}
+714
View File
@@ -0,0 +1,714 @@
// Old tests ported to Go1. This is a mess. Want to drop it one day.
// Copyright 2011 Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mux
import (
"bytes"
"net/http"
"testing"
)
// ----------------------------------------------------------------------------
// ResponseRecorder
// ----------------------------------------------------------------------------
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// ResponseRecorder is an implementation of http.ResponseWriter that
// records its mutations for later inspection in tests.
type ResponseRecorder struct {
Code int // the HTTP response code from WriteHeader
HeaderMap http.Header // the HTTP response headers
Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
Flushed bool
}
// NewRecorder returns an initialized ResponseRecorder.
func NewRecorder() *ResponseRecorder {
return &ResponseRecorder{
HeaderMap: make(http.Header),
Body: new(bytes.Buffer),
}
}
// DefaultRemoteAddr is the default remote address to return in RemoteAddr if
// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
const DefaultRemoteAddr = "1.2.3.4"
// Header returns the response headers.
func (rw *ResponseRecorder) Header() http.Header {
return rw.HeaderMap
}
// Write always succeeds and writes to rw.Body, if not nil.
func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
if rw.Body != nil {
rw.Body.Write(buf)
}
if rw.Code == 0 {
rw.Code = http.StatusOK
}
return len(buf), nil
}
// WriteHeader sets rw.Code.
func (rw *ResponseRecorder) WriteHeader(code int) {
rw.Code = code
}
// Flush sets rw.Flushed to true.
func (rw *ResponseRecorder) Flush() {
rw.Flushed = true
}
// ----------------------------------------------------------------------------
func TestRouteMatchers(t *testing.T) {
var scheme, host, path, query, method string
var headers map[string]string
var resultVars map[bool]map[string]string
router := NewRouter()
router.NewRoute().Host("{var1}.google.com").
Path("/{var2:[a-z]+}/{var3:[0-9]+}").
Queries("foo", "bar").
Methods("GET").
Schemes("https").
Headers("x-requested-with", "XMLHttpRequest")
router.NewRoute().Host("www.{var4}.com").
PathPrefix("/foo/{var5:[a-z]+}/{var6:[0-9]+}").
Queries("baz", "ding").
Methods("POST").
Schemes("http").
Headers("Content-Type", "application/json")
reset := func() {
// Everything match.
scheme = "https"
host = "www.google.com"
path = "/product/42"
query = "?foo=bar"
method = "GET"
headers = map[string]string{"X-Requested-With": "XMLHttpRequest"}
resultVars = map[bool]map[string]string{
true: {"var1": "www", "var2": "product", "var3": "42"},
false: {},
}
}
reset2 := func() {
// Everything match.
scheme = "http"
host = "www.google.com"
path = "/foo/product/42/path/that/is/ignored"
query = "?baz=ding"
method = "POST"
headers = map[string]string{"Content-Type": "application/json"}
resultVars = map[bool]map[string]string{
true: {"var4": "google", "var5": "product", "var6": "42"},
false: {},
}
}
match := func(shouldMatch bool) {
url := scheme + "://" + host + path + query
request, _ := http.NewRequest(method, url, nil)
for key, value := range headers {
request.Header.Add(key, value)
}
var routeMatch RouteMatch
matched := router.Match(request, &routeMatch)
if matched != shouldMatch {
// Need better messages. :)
if matched {
t.Errorf("Should match.")
} else {
t.Errorf("Should not match.")
}
}
if matched {
currentRoute := routeMatch.Route
if currentRoute == nil {
t.Errorf("Expected a current route.")
}
vars := routeMatch.Vars
expectedVars := resultVars[shouldMatch]
if len(vars) != len(expectedVars) {
t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars)
}
for name, value := range vars {
if expectedVars[name] != value {
t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars)
}
}
}
}
// 1st route --------------------------------------------------------------
// Everything match.
reset()
match(true)
// Scheme doesn't match.
reset()
scheme = "http"
match(false)
// Host doesn't match.
reset()
host = "www.mygoogle.com"
match(false)
// Path doesn't match.
reset()
path = "/product/notdigits"
match(false)
// Query doesn't match.
reset()
query = "?foo=baz"
match(false)
// Method doesn't match.
reset()
method = "POST"
match(false)
// Header doesn't match.
reset()
headers = map[string]string{}
match(false)
// Everything match, again.
reset()
match(true)
// 2nd route --------------------------------------------------------------
// Everything match.
reset2()
match(true)
// Scheme doesn't match.
reset2()
scheme = "https"
match(false)
// Host doesn't match.
reset2()
host = "sub.google.com"
match(false)
// Path doesn't match.
reset2()
path = "/bar/product/42"
match(false)
// Query doesn't match.
reset2()
query = "?foo=baz"
match(false)
// Method doesn't match.
reset2()
method = "GET"
match(false)
// Header doesn't match.
reset2()
headers = map[string]string{}
match(false)
// Everything match, again.
reset2()
match(true)
}
type headerMatcherTest struct {
matcher headerMatcher
headers map[string]string
result bool
}
var headerMatcherTests = []headerMatcherTest{
{
matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}),
headers: map[string]string{"X-Requested-With": "XMLHttpRequest"},
result: true,
},
{
matcher: headerMatcher(map[string]string{"x-requested-with": ""}),
headers: map[string]string{"X-Requested-With": "anything"},
result: true,
},
{
matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}),
headers: map[string]string{},
result: false,
},
}
type hostMatcherTest struct {
matcher *Route
url string
vars map[string]string
result bool
}
var hostMatcherTests = []hostMatcherTest{
{
matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"),
url: "http://abc.def.ghi/",
vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"},
result: true,
},
{
matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"),
url: "http://a.b.c/",
vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"},
result: false,
},
}
type methodMatcherTest struct {
matcher methodMatcher
method string
result bool
}
var methodMatcherTests = []methodMatcherTest{
{
matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
method: "GET",
result: true,
},
{
matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
method: "POST",
result: true,
},
{
matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
method: "PUT",
result: true,
},
{
matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
method: "DELETE",
result: false,
},
}
type pathMatcherTest struct {
matcher *Route
url string
vars map[string]string
result bool
}
var pathMatcherTests = []pathMatcherTest{
{
matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"),
url: "http://localhost:8080/123/456/789",
vars: map[string]string{"foo": "123", "bar": "456", "baz": "789"},
result: true,
},
{
matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"),
url: "http://localhost:8080/1/2/3",
vars: map[string]string{"foo": "123", "bar": "456", "baz": "789"},
result: false,
},
}
type schemeMatcherTest struct {
matcher schemeMatcher
url string
result bool
}
var schemeMatcherTests = []schemeMatcherTest{
{
matcher: schemeMatcher([]string{"http", "https"}),
url: "http://localhost:8080/",
result: true,
},
{
matcher: schemeMatcher([]string{"http", "https"}),
url: "https://localhost:8080/",
result: true,
},
{
matcher: schemeMatcher([]string{"https"}),
url: "http://localhost:8080/",
result: false,
},
{
matcher: schemeMatcher([]string{"http"}),
url: "https://localhost:8080/",
result: false,
},
}
type urlBuildingTest struct {
route *Route
vars []string
url string
}
var urlBuildingTests = []urlBuildingTest{
{
route: new(Route).Host("foo.domain.com"),
vars: []string{},
url: "http://foo.domain.com",
},
{
route: new(Route).Host("{subdomain}.domain.com"),
vars: []string{"subdomain", "bar"},
url: "http://bar.domain.com",
},
{
route: new(Route).Host("foo.domain.com").Path("/articles"),
vars: []string{},
url: "http://foo.domain.com/articles",
},
{
route: new(Route).Path("/articles"),
vars: []string{},
url: "/articles",
},
{
route: new(Route).Path("/articles/{category}/{id:[0-9]+}"),
vars: []string{"category", "technology", "id", "42"},
url: "/articles/technology/42",
},
{
route: new(Route).Host("{subdomain}.domain.com").Path("/articles/{category}/{id:[0-9]+}"),
vars: []string{"subdomain", "foo", "category", "technology", "id", "42"},
url: "http://foo.domain.com/articles/technology/42",
},
}
func TestHeaderMatcher(t *testing.T) {
for _, v := range headerMatcherTests {
request, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
for key, value := range v.headers {
request.Header.Add(key, value)
}
var routeMatch RouteMatch
result := v.matcher.Match(request, &routeMatch)
if result != v.result {
if v.result {
t.Errorf("%#v: should match %v.", v.matcher, request.Header)
} else {
t.Errorf("%#v: should not match %v.", v.matcher, request.Header)
}
}
}
}
func TestHostMatcher(t *testing.T) {
for _, v := range hostMatcherTests {
request, _ := http.NewRequest("GET", v.url, nil)
var routeMatch RouteMatch
result := v.matcher.Match(request, &routeMatch)
vars := routeMatch.Vars
if result != v.result {
if v.result {
t.Errorf("%#v: should match %v.", v.matcher, v.url)
} else {
t.Errorf("%#v: should not match %v.", v.matcher, v.url)
}
}
if result {
if len(vars) != len(v.vars) {
t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars))
}
for name, value := range vars {
if v.vars[name] != value {
t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value)
}
}
} else {
if len(vars) != 0 {
t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars))
}
}
}
}
func TestMethodMatcher(t *testing.T) {
for _, v := range methodMatcherTests {
request, _ := http.NewRequest(v.method, "http://localhost:8080/", nil)
var routeMatch RouteMatch
result := v.matcher.Match(request, &routeMatch)
if result != v.result {
if v.result {
t.Errorf("%#v: should match %v.", v.matcher, v.method)
} else {
t.Errorf("%#v: should not match %v.", v.matcher, v.method)
}
}
}
}
func TestPathMatcher(t *testing.T) {
for _, v := range pathMatcherTests {
request, _ := http.NewRequest("GET", v.url, nil)
var routeMatch RouteMatch
result := v.matcher.Match(request, &routeMatch)
vars := routeMatch.Vars
if result != v.result {
if v.result {
t.Errorf("%#v: should match %v.", v.matcher, v.url)
} else {
t.Errorf("%#v: should not match %v.", v.matcher, v.url)
}
}
if result {
if len(vars) != len(v.vars) {
t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars))
}
for name, value := range vars {
if v.vars[name] != value {
t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value)
}
}
} else {
if len(vars) != 0 {
t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars))
}
}
}
}
func TestSchemeMatcher(t *testing.T) {
for _, v := range schemeMatcherTests {
request, _ := http.NewRequest("GET", v.url, nil)
var routeMatch RouteMatch
result := v.matcher.Match(request, &routeMatch)
if result != v.result {
if v.result {
t.Errorf("%#v: should match %v.", v.matcher, v.url)
} else {
t.Errorf("%#v: should not match %v.", v.matcher, v.url)
}
}
}
}
func TestUrlBuilding(t *testing.T) {
for _, v := range urlBuildingTests {
u, _ := v.route.URL(v.vars...)
url := u.String()
if url != v.url {
t.Errorf("expected %v, got %v", v.url, url)
/*
reversePath := ""
reverseHost := ""
if v.route.pathTemplate != nil {
reversePath = v.route.pathTemplate.Reverse
}
if v.route.hostTemplate != nil {
reverseHost = v.route.hostTemplate.Reverse
}
t.Errorf("%#v:\nexpected: %q\ngot: %q\nreverse path: %q\nreverse host: %q", v.route, v.url, url, reversePath, reverseHost)
*/
}
}
ArticleHandler := func(w http.ResponseWriter, r *http.Request) {
}
router := NewRouter()
router.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).Name("article")
url, _ := router.Get("article").URL("category", "technology", "id", "42")
expected := "/articles/technology/42"
if url.String() != expected {
t.Errorf("Expected %v, got %v", expected, url.String())
}
}
func TestMatchedRouteName(t *testing.T) {
routeName := "stock"
router := NewRouter()
route := router.NewRoute().Path("/products/").Name(routeName)
url := "http://www.domain.com/products/"
request, _ := http.NewRequest("GET", url, nil)
var rv RouteMatch
ok := router.Match(request, &rv)
if !ok || rv.Route != route {
t.Errorf("Expected same route, got %+v.", rv.Route)
}
retName := rv.Route.GetName()
if retName != routeName {
t.Errorf("Expected %q, got %q.", routeName, retName)
}
}
func TestSubRouting(t *testing.T) {
// Example from docs.
router := NewRouter()
subrouter := router.NewRoute().Host("www.domain.com").Subrouter()
route := subrouter.NewRoute().Path("/products/").Name("products")
url := "http://www.domain.com/products/"
request, _ := http.NewRequest("GET", url, nil)
var rv RouteMatch
ok := router.Match(request, &rv)
if !ok || rv.Route != route {
t.Errorf("Expected same route, got %+v.", rv.Route)
}
u, _ := router.Get("products").URL()
builtUrl := u.String()
// Yay, subroute aware of the domain when building!
if builtUrl != url {
t.Errorf("Expected %q, got %q.", url, builtUrl)
}
}
func TestVariableNames(t *testing.T) {
route := new(Route).Host("{arg1}.domain.com").Path("/{arg1}/{arg2:[0-9]+}")
if route.err == nil {
t.Errorf("Expected error for duplicated variable names")
}
}
func TestRedirectSlash(t *testing.T) {
var route *Route
var routeMatch RouteMatch
r := NewRouter()
r.StrictSlash(false)
route = r.NewRoute()
if route.strictSlash != false {
t.Errorf("Expected false redirectSlash.")
}
r.StrictSlash(true)
route = r.NewRoute()
if route.strictSlash != true {
t.Errorf("Expected true redirectSlash.")
}
route = new(Route)
route.strictSlash = true
route.Path("/{arg1}/{arg2:[0-9]+}/")
request, _ := http.NewRequest("GET", "http://localhost/foo/123", nil)
routeMatch = RouteMatch{}
_ = route.Match(request, &routeMatch)
vars := routeMatch.Vars
if vars["arg1"] != "foo" {
t.Errorf("Expected foo.")
}
if vars["arg2"] != "123" {
t.Errorf("Expected 123.")
}
rsp := NewRecorder()
routeMatch.Handler.ServeHTTP(rsp, request)
if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123/" {
t.Errorf("Expected redirect header.")
}
route = new(Route)
route.strictSlash = true
route.Path("/{arg1}/{arg2:[0-9]+}")
request, _ = http.NewRequest("GET", "http://localhost/foo/123/", nil)
routeMatch = RouteMatch{}
_ = route.Match(request, &routeMatch)
vars = routeMatch.Vars
if vars["arg1"] != "foo" {
t.Errorf("Expected foo.")
}
if vars["arg2"] != "123" {
t.Errorf("Expected 123.")
}
rsp = NewRecorder()
routeMatch.Handler.ServeHTTP(rsp, request)
if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123" {
t.Errorf("Expected redirect header.")
}
}
// Test for the new regexp library, still not available in stable Go.
func TestNewRegexp(t *testing.T) {
var p *routeRegexp
var matches []string
tests := map[string]map[string][]string{
"/{foo:a{2}}": {
"/a": nil,
"/aa": {"aa"},
"/aaa": nil,
"/aaaa": nil,
},
"/{foo:a{2,}}": {
"/a": nil,
"/aa": {"aa"},
"/aaa": {"aaa"},
"/aaaa": {"aaaa"},
},
"/{foo:a{2,3}}": {
"/a": nil,
"/aa": {"aa"},
"/aaa": {"aaa"},
"/aaaa": nil,
},
"/{foo:[a-z]{3}}/{bar:[a-z]{2}}": {
"/a": nil,
"/ab": nil,
"/abc": nil,
"/abcd": nil,
"/abc/ab": {"abc", "ab"},
"/abc/abc": nil,
"/abcd/ab": nil,
},
`/{foo:\w{3,}}/{bar:\d{2,}}`: {
"/a": nil,
"/ab": nil,
"/abc": nil,
"/abc/1": nil,
"/abc/12": {"abc", "12"},
"/abcd/12": {"abcd", "12"},
"/abcd/123": {"abcd", "123"},
},
}
for pattern, paths := range tests {
p, _ = newRouteRegexp(pattern, false, false, false, false)
for path, result := range paths {
matches = p.regexp.FindStringSubmatch(path)
if result == nil {
if matches != nil {
t.Errorf("%v should not match %v.", pattern, path)
}
} else {
if len(matches) != len(result)+1 {
t.Errorf("Expected %v matches, got %v.", len(result)+1, len(matches))
} else {
for k, v := range result {
if matches[k+1] != v {
t.Errorf("Expected %v, got %v.", v, matches[k+1])
}
}
}
}
}
}
}
+276
View File
@@ -0,0 +1,276 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mux
import (
"bytes"
"fmt"
"net/http"
"net/url"
"regexp"
"strings"
)
// newRouteRegexp parses a route template and returns a routeRegexp,
// used to match a host, a path or a query string.
//
// It will extract named variables, assemble a regexp to be matched, create
// a "reverse" template to build URLs and compile regexps to validate variable
// values used in URL building.
//
// Previously we accepted only Python-like identifiers for variable
// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
// name and pattern can't be empty, and names can't contain a colon.
func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash bool) (*routeRegexp, error) {
// Check if it is well-formed.
idxs, errBraces := braceIndices(tpl)
if errBraces != nil {
return nil, errBraces
}
// Backup the original.
template := tpl
// Now let's parse it.
defaultPattern := "[^/]+"
if matchQuery {
defaultPattern = "[^?&]+"
matchPrefix = true
} else if matchHost {
defaultPattern = "[^.]+"
matchPrefix = false
}
// Only match strict slash if not matching
if matchPrefix || matchHost || matchQuery {
strictSlash = false
}
// Set a flag for strictSlash.
endSlash := false
if strictSlash && strings.HasSuffix(tpl, "/") {
tpl = tpl[:len(tpl)-1]
endSlash = true
}
varsN := make([]string, len(idxs)/2)
varsR := make([]*regexp.Regexp, len(idxs)/2)
pattern := bytes.NewBufferString("")
if !matchQuery {
pattern.WriteByte('^')
}
reverse := bytes.NewBufferString("")
var end int
var err error
for i := 0; i < len(idxs); i += 2 {
// Set all values we are interested in.
raw := tpl[end:idxs[i]]
end = idxs[i+1]
parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2)
name := parts[0]
patt := defaultPattern
if len(parts) == 2 {
patt = parts[1]
}
// Name or pattern can't be empty.
if name == "" || patt == "" {
return nil, fmt.Errorf("mux: missing name or pattern in %q",
tpl[idxs[i]:end])
}
// Build the regexp pattern.
fmt.Fprintf(pattern, "%s(%s)", regexp.QuoteMeta(raw), patt)
// Build the reverse template.
fmt.Fprintf(reverse, "%s%%s", raw)
// Append variable name and compiled pattern.
varsN[i/2] = name
varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
if err != nil {
return nil, err
}
}
// Add the remaining.
raw := tpl[end:]
pattern.WriteString(regexp.QuoteMeta(raw))
if strictSlash {
pattern.WriteString("[/]?")
}
if !matchPrefix {
pattern.WriteByte('$')
}
reverse.WriteString(raw)
if endSlash {
reverse.WriteByte('/')
}
// Compile full regexp.
reg, errCompile := regexp.Compile(pattern.String())
if errCompile != nil {
return nil, errCompile
}
// Done!
return &routeRegexp{
template: template,
matchHost: matchHost,
matchQuery: matchQuery,
strictSlash: strictSlash,
regexp: reg,
reverse: reverse.String(),
varsN: varsN,
varsR: varsR,
}, nil
}
// routeRegexp stores a regexp to match a host or path and information to
// collect and validate route variables.
type routeRegexp struct {
// The unmodified template.
template string
// True for host match, false for path or query string match.
matchHost bool
// True for query string match, false for path and host match.
matchQuery bool
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
strictSlash bool
// Expanded regexp.
regexp *regexp.Regexp
// Reverse template.
reverse string
// Variable names.
varsN []string
// Variable regexps (validators).
varsR []*regexp.Regexp
}
// Match matches the regexp against the URL host or path.
func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
if !r.matchHost {
if r.matchQuery {
return r.regexp.MatchString(req.URL.RawQuery)
} else {
return r.regexp.MatchString(req.URL.Path)
}
}
return r.regexp.MatchString(getHost(req))
}
// url builds a URL part using the given values.
func (r *routeRegexp) url(pairs ...string) (string, error) {
values, err := mapFromPairs(pairs...)
if err != nil {
return "", err
}
urlValues := make([]interface{}, len(r.varsN))
for k, v := range r.varsN {
value, ok := values[v]
if !ok {
return "", fmt.Errorf("mux: missing route variable %q", v)
}
urlValues[k] = value
}
rv := fmt.Sprintf(r.reverse, urlValues...)
if !r.regexp.MatchString(rv) {
// The URL is checked against the full regexp, instead of checking
// individual variables. This is faster but to provide a good error
// message, we check individual regexps if the URL doesn't match.
for k, v := range r.varsN {
if !r.varsR[k].MatchString(values[v]) {
return "", fmt.Errorf(
"mux: variable %q doesn't match, expected %q", values[v],
r.varsR[k].String())
}
}
}
return rv, nil
}
// braceIndices returns the first level curly brace indices from a string.
// It returns an error in case of unbalanced braces.
func braceIndices(s string) ([]int, error) {
var level, idx int
idxs := make([]int, 0)
for i := 0; i < len(s); i++ {
switch s[i] {
case '{':
if level++; level == 1 {
idx = i
}
case '}':
if level--; level == 0 {
idxs = append(idxs, idx, i+1)
} else if level < 0 {
return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
}
}
}
if level != 0 {
return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
}
return idxs, nil
}
// ----------------------------------------------------------------------------
// routeRegexpGroup
// ----------------------------------------------------------------------------
// routeRegexpGroup groups the route matchers that carry variables.
type routeRegexpGroup struct {
host *routeRegexp
path *routeRegexp
queries []*routeRegexp
}
// setMatch extracts the variables from the URL once a route matches.
func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
// Store host variables.
if v.host != nil {
hostVars := v.host.regexp.FindStringSubmatch(getHost(req))
if hostVars != nil {
for k, v := range v.host.varsN {
m.Vars[v] = hostVars[k+1]
}
}
}
// Store path variables.
if v.path != nil {
pathVars := v.path.regexp.FindStringSubmatch(req.URL.Path)
if pathVars != nil {
for k, v := range v.path.varsN {
m.Vars[v] = pathVars[k+1]
}
// Check if we should redirect.
if v.path.strictSlash {
p1 := strings.HasSuffix(req.URL.Path, "/")
p2 := strings.HasSuffix(v.path.template, "/")
if p1 != p2 {
u, _ := url.Parse(req.URL.String())
if p1 {
u.Path = u.Path[:len(u.Path)-1]
} else {
u.Path += "/"
}
m.Handler = http.RedirectHandler(u.String(), 301)
}
}
}
}
// Store query string variables.
rawQuery := req.URL.RawQuery
for _, q := range v.queries {
queryVars := q.regexp.FindStringSubmatch(rawQuery)
if queryVars != nil {
for k, v := range q.varsN {
m.Vars[v] = queryVars[k+1]
}
}
}
}
// getHost tries its best to return the request host.
func getHost(r *http.Request) string {
if r.URL.IsAbs() {
return r.URL.Host
}
host := r.Host
// Slice off any port information.
if i := strings.Index(host, ":"); i != -1 {
host = host[:i]
}
return host
}
+524
View File
@@ -0,0 +1,524 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mux
import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
)
// Route stores information to match a request and build URLs.
type Route struct {
// Parent where the route was registered (a Router).
parent parentRoute
// Request handler for the route.
handler http.Handler
// List of matchers.
matchers []matcher
// Manager for the variables from host and path.
regexp *routeRegexpGroup
// If true, when the path pattern is "/path/", accessing "/path" will
// redirect to the former and vice versa.
strictSlash bool
// If true, this route never matches: it is only used to build URLs.
buildOnly bool
// The name used to build URLs.
name string
// Error resulted from building a route.
err error
}
// Match matches the route against the request.
func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
if r.buildOnly || r.err != nil {
return false
}
// Match everything.
for _, m := range r.matchers {
if matched := m.Match(req, match); !matched {
return false
}
}
// Yay, we have a match. Let's collect some info about it.
if match.Route == nil {
match.Route = r
}
if match.Handler == nil {
match.Handler = r.handler
}
if match.Vars == nil {
match.Vars = make(map[string]string)
}
// Set variables.
if r.regexp != nil {
r.regexp.setMatch(req, match, r)
}
return true
}
// ----------------------------------------------------------------------------
// Route attributes
// ----------------------------------------------------------------------------
// GetError returns an error resulted from building the route, if any.
func (r *Route) GetError() error {
return r.err
}
// BuildOnly sets the route to never match: it is only used to build URLs.
func (r *Route) BuildOnly() *Route {
r.buildOnly = true
return r
}
// Handler --------------------------------------------------------------------
// Handler sets a handler for the route.
func (r *Route) Handler(handler http.Handler) *Route {
if r.err == nil {
r.handler = handler
}
return r
}
// HandlerFunc sets a handler function for the route.
func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route {
return r.Handler(http.HandlerFunc(f))
}
// GetHandler returns the handler for the route, if any.
func (r *Route) GetHandler() http.Handler {
return r.handler
}
// Name -----------------------------------------------------------------------
// Name sets the name for the route, used to build URLs.
// If the name was registered already it will be overwritten.
func (r *Route) Name(name string) *Route {
if r.name != "" {
r.err = fmt.Errorf("mux: route already has name %q, can't set %q",
r.name, name)
}
if r.err == nil {
r.name = name
r.getNamedRoutes()[name] = r
}
return r
}
// GetName returns the name for the route, if any.
func (r *Route) GetName() string {
return r.name
}
// ----------------------------------------------------------------------------
// Matchers
// ----------------------------------------------------------------------------
// matcher types try to match a request.
type matcher interface {
Match(*http.Request, *RouteMatch) bool
}
// addMatcher adds a matcher to the route.
func (r *Route) addMatcher(m matcher) *Route {
if r.err == nil {
r.matchers = append(r.matchers, m)
}
return r
}
// addRegexpMatcher adds a host or path matcher and builder to a route.
func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery bool) error {
if r.err != nil {
return r.err
}
r.regexp = r.getRegexpGroup()
if !matchHost && !matchQuery {
if len(tpl) == 0 || tpl[0] != '/' {
return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
}
if r.regexp.path != nil {
tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
}
}
rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash)
if err != nil {
return err
}
for _, q := range r.regexp.queries {
if err = uniqueVars(rr.varsN, q.varsN); err != nil {
return err
}
}
if matchHost {
if r.regexp.path != nil {
if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
return err
}
}
r.regexp.host = rr
} else {
if r.regexp.host != nil {
if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil {
return err
}
}
if matchQuery {
r.regexp.queries = append(r.regexp.queries, rr)
} else {
r.regexp.path = rr
}
}
r.addMatcher(rr)
return nil
}
// Headers --------------------------------------------------------------------
// headerMatcher matches the request against header values.
type headerMatcher map[string]string
func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
return matchMap(m, r.Header, true)
}
// Headers adds a matcher for request header values.
// It accepts a sequence of key/value pairs to be matched. For example:
//
// r := mux.NewRouter()
// r.Headers("Content-Type", "application/json",
// "X-Requested-With", "XMLHttpRequest")
//
// The above route will only match if both request header values match.
//
// It the value is an empty string, it will match any value if the key is set.
func (r *Route) Headers(pairs ...string) *Route {
if r.err == nil {
var headers map[string]string
headers, r.err = mapFromPairs(pairs...)
return r.addMatcher(headerMatcher(headers))
}
return r
}
// Host -----------------------------------------------------------------------
// Host adds a matcher for the URL host.
// It accepts a template with zero or more URL variables enclosed by {}.
// Variables can define an optional regexp pattern to me matched:
//
// - {name} matches anything until the next dot.
//
// - {name:pattern} matches the given regexp pattern.
//
// For example:
//
// r := mux.NewRouter()
// r.Host("www.domain.com")
// r.Host("{subdomain}.domain.com")
// r.Host("{subdomain:[a-z]+}.domain.com")
//
// Variable names must be unique in a given route. They can be retrieved
// calling mux.Vars(request).
func (r *Route) Host(tpl string) *Route {
r.err = r.addRegexpMatcher(tpl, true, false, false)
return r
}
// MatcherFunc ----------------------------------------------------------------
// MatcherFunc is the function signature used by custom matchers.
type MatcherFunc func(*http.Request, *RouteMatch) bool
func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
return m(r, match)
}
// MatcherFunc adds a custom function to be used as request matcher.
func (r *Route) MatcherFunc(f MatcherFunc) *Route {
return r.addMatcher(f)
}
// Methods --------------------------------------------------------------------
// methodMatcher matches the request against HTTP methods.
type methodMatcher []string
func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool {
return matchInArray(m, r.Method)
}
// Methods adds a matcher for HTTP methods.
// It accepts a sequence of one or more methods to be matched, e.g.:
// "GET", "POST", "PUT".
func (r *Route) Methods(methods ...string) *Route {
for k, v := range methods {
methods[k] = strings.ToUpper(v)
}
return r.addMatcher(methodMatcher(methods))
}
// Path -----------------------------------------------------------------------
// Path adds a matcher for the URL path.
// It accepts a template with zero or more URL variables enclosed by {}. The
// template must start with a "/".
// Variables can define an optional regexp pattern to me matched:
//
// - {name} matches anything until the next slash.
//
// - {name:pattern} matches the given regexp pattern.
//
// For example:
//
// r := mux.NewRouter()
// r.Path("/products/").Handler(ProductsHandler)
// r.Path("/products/{key}").Handler(ProductsHandler)
// r.Path("/articles/{category}/{id:[0-9]+}").
// Handler(ArticleHandler)
//
// Variable names must be unique in a given route. They can be retrieved
// calling mux.Vars(request).
func (r *Route) Path(tpl string) *Route {
r.err = r.addRegexpMatcher(tpl, false, false, false)
return r
}
// PathPrefix -----------------------------------------------------------------
// PathPrefix adds a matcher for the URL path prefix. This matches if the given
// template is a prefix of the full URL path. See Route.Path() for details on
// the tpl argument.
//
// Note that it does not treat slashes specially ("/foobar/" will be matched by
// the prefix "/foo") so you may want to use a trailing slash here.
//
// Also note that the setting of Router.StrictSlash() has no effect on routes
// with a PathPrefix matcher.
func (r *Route) PathPrefix(tpl string) *Route {
r.err = r.addRegexpMatcher(tpl, false, true, false)
return r
}
// Query ----------------------------------------------------------------------
// Queries adds a matcher for URL query values.
// It accepts a sequence of key/value pairs. Values may define variables.
// For example:
//
// r := mux.NewRouter()
// r.Queries("foo", "bar", "id", "{id:[0-9]+}")
//
// The above route will only match if the URL contains the defined queries
// values, e.g.: ?foo=bar&id=42.
//
// It the value is an empty string, it will match any value if the key is set.
//
// Variables can define an optional regexp pattern to me matched:
//
// - {name} matches anything until the next slash.
//
// - {name:pattern} matches the given regexp pattern.
func (r *Route) Queries(pairs ...string) *Route {
length := len(pairs)
if length%2 != 0 {
r.err = fmt.Errorf(
"mux: number of parameters must be multiple of 2, got %v", pairs)
return nil
}
for i := 0; i < length; i += 2 {
if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, true, true); r.err != nil {
return r
}
}
return r
}
// Schemes --------------------------------------------------------------------
// schemeMatcher matches the request against URL schemes.
type schemeMatcher []string
func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool {
return matchInArray(m, r.URL.Scheme)
}
// Schemes adds a matcher for URL schemes.
// It accepts a sequence of schemes to be matched, e.g.: "http", "https".
func (r *Route) Schemes(schemes ...string) *Route {
for k, v := range schemes {
schemes[k] = strings.ToLower(v)
}
return r.addMatcher(schemeMatcher(schemes))
}
// Subrouter ------------------------------------------------------------------
// Subrouter creates a subrouter for the route.
//
// It will test the inner routes only if the parent route matched. For example:
//
// r := mux.NewRouter()
// s := r.Host("www.domain.com").Subrouter()
// s.HandleFunc("/products/", ProductsHandler)
// s.HandleFunc("/products/{key}", ProductHandler)
// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
//
// Here, the routes registered in the subrouter won't be tested if the host
// doesn't match.
func (r *Route) Subrouter() *Router {
router := &Router{parent: r, strictSlash: r.strictSlash}
r.addMatcher(router)
return router
}
// ----------------------------------------------------------------------------
// URL building
// ----------------------------------------------------------------------------
// URL builds a URL for the route.
//
// It accepts a sequence of key/value pairs for the route variables. For
// example, given this route:
//
// r := mux.NewRouter()
// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
// Name("article")
//
// ...a URL for it can be built using:
//
// url, err := r.Get("article").URL("category", "technology", "id", "42")
//
// ...which will return an url.URL with the following path:
//
// "/articles/technology/42"
//
// This also works for host variables:
//
// r := mux.NewRouter()
// r.Host("{subdomain}.domain.com").
// HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
// Name("article")
//
// // url.String() will be "http://news.domain.com/articles/technology/42"
// url, err := r.Get("article").URL("subdomain", "news",
// "category", "technology",
// "id", "42")
//
// All variables defined in the route are required, and their values must
// conform to the corresponding patterns.
func (r *Route) URL(pairs ...string) (*url.URL, error) {
if r.err != nil {
return nil, r.err
}
if r.regexp == nil {
return nil, errors.New("mux: route doesn't have a host or path")
}
var scheme, host, path string
var err error
if r.regexp.host != nil {
// Set a default scheme.
scheme = "http"
if host, err = r.regexp.host.url(pairs...); err != nil {
return nil, err
}
}
if r.regexp.path != nil {
if path, err = r.regexp.path.url(pairs...); err != nil {
return nil, err
}
}
return &url.URL{
Scheme: scheme,
Host: host,
Path: path,
}, nil
}
// URLHost builds the host part of the URL for a route. See Route.URL().
//
// The route must have a host defined.
func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
if r.err != nil {
return nil, r.err
}
if r.regexp == nil || r.regexp.host == nil {
return nil, errors.New("mux: route doesn't have a host")
}
host, err := r.regexp.host.url(pairs...)
if err != nil {
return nil, err
}
return &url.URL{
Scheme: "http",
Host: host,
}, nil
}
// URLPath builds the path part of the URL for a route. See Route.URL().
//
// The route must have a path defined.
func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
if r.err != nil {
return nil, r.err
}
if r.regexp == nil || r.regexp.path == nil {
return nil, errors.New("mux: route doesn't have a path")
}
path, err := r.regexp.path.url(pairs...)
if err != nil {
return nil, err
}
return &url.URL{
Path: path,
}, nil
}
// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------
// parentRoute allows routes to know about parent host and path definitions.
type parentRoute interface {
getNamedRoutes() map[string]*Route
getRegexpGroup() *routeRegexpGroup
}
// getNamedRoutes returns the map where named routes are registered.
func (r *Route) getNamedRoutes() map[string]*Route {
if r.parent == nil {
// During tests router is not always set.
r.parent = NewRouter()
}
return r.parent.getNamedRoutes()
}
// getRegexpGroup returns regexp definitions from this route.
func (r *Route) getRegexpGroup() *routeRegexpGroup {
if r.regexp == nil {
if r.parent == nil {
// During tests router is not always set.
r.parent = NewRouter()
}
regexp := r.parent.getRegexpGroup()
if regexp == nil {
r.regexp = new(routeRegexpGroup)
} else {
// Copy.
r.regexp = &routeRegexpGroup{
host: regexp.host,
path: regexp.path,
queries: regexp.queries,
}
}
}
return r.regexp
}
+4
View File
@@ -0,0 +1,4 @@
_*
*.swp
*.[568]
[568].out
+25
View File
@@ -0,0 +1,25 @@
Gocheck - A rich testing framework for Go
Copyright (c) 2010-2013 Gustavo Niemeyer <gustavo@niemeyer.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+20
View File
@@ -0,0 +1,20 @@
Instructions
============
Install the package with:
go get github.com/minio/check
Import it with:
import "github.com/minio/check"
and use _check_ as the package name inside the code.
For more details, visit the project page:
* http://labix.org/gocheck
and the API documentation:
* https://gopkg.in/check.v1
+2
View File
@@ -0,0 +1,2 @@
- Assert(slice, Contains, item)
- Parallel test support
+163
View File
@@ -0,0 +1,163 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package check
import (
"fmt"
"runtime"
"time"
)
var memStats runtime.MemStats
// testingB is a type passed to Benchmark functions to manage benchmark
// timing and to specify the number of iterations to run.
type timer struct {
start time.Time // Time test or benchmark started
duration time.Duration
N int
bytes int64
timerOn bool
benchTime time.Duration
// The initial states of memStats.Mallocs and memStats.TotalAlloc.
startAllocs uint64
startBytes uint64
// The net total of this test after being run.
netAllocs uint64
netBytes uint64
}
// StartTimer starts timing a test. This function is called automatically
// before a benchmark starts, but it can also used to resume timing after
// a call to StopTimer.
func (c *C) StartTimer() {
if !c.timerOn {
c.start = time.Now()
c.timerOn = true
runtime.ReadMemStats(&memStats)
c.startAllocs = memStats.Mallocs
c.startBytes = memStats.TotalAlloc
}
}
// StopTimer stops timing a test. This can be used to pause the timer
// while performing complex initialization that you don't
// want to measure.
func (c *C) StopTimer() {
if c.timerOn {
c.duration += time.Now().Sub(c.start)
c.timerOn = false
runtime.ReadMemStats(&memStats)
c.netAllocs += memStats.Mallocs - c.startAllocs
c.netBytes += memStats.TotalAlloc - c.startBytes
}
}
// ResetTimer sets the elapsed benchmark time to zero.
// It does not affect whether the timer is running.
func (c *C) ResetTimer() {
if c.timerOn {
c.start = time.Now()
runtime.ReadMemStats(&memStats)
c.startAllocs = memStats.Mallocs
c.startBytes = memStats.TotalAlloc
}
c.duration = 0
c.netAllocs = 0
c.netBytes = 0
}
// SetBytes informs the number of bytes that the benchmark processes
// on each iteration. If this is called in a benchmark it will also
// report MB/s.
func (c *C) SetBytes(n int64) {
c.bytes = n
}
func (c *C) nsPerOp() int64 {
if c.N <= 0 {
return 0
}
return c.duration.Nanoseconds() / int64(c.N)
}
func (c *C) mbPerSec() float64 {
if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 {
return 0
}
return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds()
}
func (c *C) timerString() string {
if c.N <= 0 {
return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9)
}
mbs := c.mbPerSec()
mb := ""
if mbs != 0 {
mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
}
nsop := c.nsPerOp()
ns := fmt.Sprintf("%10d ns/op", nsop)
if c.N > 0 && nsop < 100 {
// The format specifiers here make sure that
// the ones digits line up for all three possible formats.
if nsop < 10 {
ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
} else {
ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
}
}
memStats := ""
if c.benchMem {
allocedBytes := fmt.Sprintf("%8d B/op", int64(c.netBytes)/int64(c.N))
allocs := fmt.Sprintf("%8d allocs/op", int64(c.netAllocs)/int64(c.N))
memStats = fmt.Sprintf("\t%s\t%s", allocedBytes, allocs)
}
return fmt.Sprintf("%8d\t%s%s%s", c.N, ns, mb, memStats)
}
func min(x, y int) int {
if x > y {
return y
}
return x
}
func max(x, y int) int {
if x < y {
return y
}
return x
}
// roundDown10 rounds a number down to the nearest power of 10.
func roundDown10(n int) int {
var tens = 0
// tens = floor(log_10(n))
for n > 10 {
n = n / 10
tens++
}
// result = 10^tens
result := 1
for i := 0; i < tens; i++ {
result *= 10
}
return result
}
// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
func roundUp(n int) int {
base := roundDown10(n)
if n < (2 * base) {
return 2 * base
}
if n < (5 * base) {
return 5 * base
}
return 10 * base
}
+91
View File
@@ -0,0 +1,91 @@
// These tests verify the test running logic.
package check_test
import (
. "github.com/minio/check"
"time"
)
var benchmarkS = Suite(&BenchmarkS{})
type BenchmarkS struct{}
func (s *BenchmarkS) TestCountSuite(c *C) {
suitesRun += 1
}
func (s *BenchmarkS) TestBasicTestTiming(c *C) {
helper := FixtureHelper{sleepOn: "Test1", sleep: 1000000 * time.Nanosecond}
output := String{}
runConf := RunConf{Output: &output, Verbose: true}
Run(&helper, &runConf)
expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test1\t0\\.001s\n" +
"PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test2\t0\\.000s\n"
c.Assert(output.value, Matches, expected)
}
func (s *BenchmarkS) TestStreamTestTiming(c *C) {
helper := FixtureHelper{sleepOn: "SetUpSuite", sleep: 1000000 * time.Nanosecond}
output := String{}
runConf := RunConf{Output: &output, Stream: true}
Run(&helper, &runConf)
expected := "(?s).*\nPASS: check_test\\.go:[0-9]+: FixtureHelper\\.SetUpSuite\t *0\\.001s\n.*"
c.Assert(output.value, Matches, expected)
}
func (s *BenchmarkS) TestBenchmark(c *C) {
helper := FixtureHelper{sleep: 100000}
output := String{}
runConf := RunConf{
Output: &output,
Benchmark: true,
BenchmarkTime: 10000000,
Filter: "Benchmark1",
}
Run(&helper, &runConf)
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Benchmark1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "SetUpTest")
c.Check(helper.calls[5], Equals, "Benchmark1")
c.Check(helper.calls[6], Equals, "TearDownTest")
// ... and more.
expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark1\t *100\t *[12][0-9]{5} ns/op\n"
c.Assert(output.value, Matches, expected)
}
func (s *BenchmarkS) TestBenchmarkBytes(c *C) {
helper := FixtureHelper{sleep: 100000}
output := String{}
runConf := RunConf{
Output: &output,
Benchmark: true,
BenchmarkTime: 10000000,
Filter: "Benchmark2",
}
Run(&helper, &runConf)
expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark2\t *100\t *[12][0-9]{5} ns/op\t *[4-9]\\.[0-9]{2} MB/s\n"
c.Assert(output.value, Matches, expected)
}
func (s *BenchmarkS) TestBenchmarkMem(c *C) {
helper := FixtureHelper{sleep: 100000}
output := String{}
runConf := RunConf{
Output: &output,
Benchmark: true,
BenchmarkMem: true,
BenchmarkTime: 10000000,
Filter: "Benchmark3",
}
Run(&helper, &runConf)
expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark3\t *100\t *[12][0-9]{5} ns/op\t *[0-9]+ B/op\t *[1-9] allocs/op\n"
c.Assert(output.value, Matches, expected)
}
+82
View File
@@ -0,0 +1,82 @@
// These initial tests are for bootstrapping. They verify that we can
// basically use the testing infrastructure itself to check if the test
// system is working.
//
// These tests use will break down the test runner badly in case of
// errors because if they simply fail, we can't be sure the developer
// will ever see anything (because failing means the failing system
// somehow isn't working! :-)
//
// Do not assume *any* internal functionality works as expected besides
// what's actually tested here.
package check_test
import (
"fmt"
"github.com/minio/check"
"strings"
)
type BootstrapS struct{}
var boostrapS = check.Suite(&BootstrapS{})
func (s *BootstrapS) TestCountSuite(c *check.C) {
suitesRun += 1
}
func (s *BootstrapS) TestFailedAndFail(c *check.C) {
if c.Failed() {
critical("c.Failed() must be false first!")
}
c.Fail()
if !c.Failed() {
critical("c.Fail() didn't put the test in a failed state!")
}
c.Succeed()
}
func (s *BootstrapS) TestFailedAndSucceed(c *check.C) {
c.Fail()
c.Succeed()
if c.Failed() {
critical("c.Succeed() didn't put the test back in a non-failed state")
}
}
func (s *BootstrapS) TestLogAndGetTestLog(c *check.C) {
c.Log("Hello there!")
log := c.GetTestLog()
if log != "Hello there!\n" {
critical(fmt.Sprintf("Log() or GetTestLog() is not working! Got: %#v", log))
}
}
func (s *BootstrapS) TestLogfAndGetTestLog(c *check.C) {
c.Logf("Hello %v", "there!")
log := c.GetTestLog()
if log != "Hello there!\n" {
critical(fmt.Sprintf("Logf() or GetTestLog() is not working! Got: %#v", log))
}
}
func (s *BootstrapS) TestRunShowsErrors(c *check.C) {
output := String{}
check.Run(&FailHelper{}, &check.RunConf{Output: &output})
if strings.Index(output.value, "Expected failure!") == -1 {
critical(fmt.Sprintf("RunWithWriter() output did not contain the "+
"expected failure! Got: %#v",
output.value))
}
}
func (s *BootstrapS) TestRunDoesntShowSuccesses(c *check.C) {
output := String{}
check.Run(&SuccessHelper{}, &check.RunConf{Output: &output})
if strings.Index(output.value, "Expected success!") != -1 {
critical(fmt.Sprintf("RunWithWriter() output contained a successful "+
"test! Got: %#v",
output.value))
}
}
+945
View File
@@ -0,0 +1,945 @@
// Package check is a rich testing extension for Go's testing package.
//
// For details about the project, see:
//
// http://labix.org/gocheck
//
package check
import (
"bytes"
"errors"
"fmt"
"io"
"math/rand"
"os"
"path"
"path/filepath"
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
// -----------------------------------------------------------------------
// Internal type which deals with suite method calling.
const (
fixtureKd = iota
testKd
)
type funcKind int
const (
succeededSt = iota
failedSt
skippedSt
panickedSt
fixturePanickedSt
missedSt
)
type funcStatus int
// A method value can't reach its own Method structure.
type methodType struct {
reflect.Value
Info reflect.Method
}
func newMethod(receiver reflect.Value, i int) *methodType {
return &methodType{receiver.Method(i), receiver.Type().Method(i)}
}
func (method *methodType) PC() uintptr {
return method.Info.Func.Pointer()
}
func (method *methodType) suiteName() string {
t := method.Info.Type.In(0)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t.Name()
}
func (method *methodType) String() string {
return method.suiteName() + "." + method.Info.Name
}
func (method *methodType) matches(re *regexp.Regexp) bool {
return (re.MatchString(method.Info.Name) ||
re.MatchString(method.suiteName()) ||
re.MatchString(method.String()))
}
type C struct {
method *methodType
kind funcKind
testName string
status funcStatus
logb *logger
logw io.Writer
done chan *C
reason string
mustFail bool
tempDir *tempDir
benchMem bool
startTime time.Time
timer
}
func (c *C) stopNow() {
runtime.Goexit()
}
// logger is a concurrency safe byte.Buffer
type logger struct {
sync.Mutex
writer bytes.Buffer
}
func (l *logger) Write(buf []byte) (int, error) {
l.Lock()
defer l.Unlock()
return l.writer.Write(buf)
}
func (l *logger) WriteTo(w io.Writer) (int64, error) {
l.Lock()
defer l.Unlock()
return l.writer.WriteTo(w)
}
func (l *logger) String() string {
l.Lock()
defer l.Unlock()
return l.writer.String()
}
// -----------------------------------------------------------------------
// Handling of temporary files and directories.
type tempDir struct {
sync.Mutex
path string
counter int
}
func (td *tempDir) newPath() string {
td.Lock()
defer td.Unlock()
if td.path == "" {
var err error
for i := 0; i != 100; i++ {
path := fmt.Sprintf("%s%ccheck-%d", os.TempDir(), os.PathSeparator, rand.Int())
if err = os.Mkdir(path, 0700); err == nil {
td.path = path
break
}
}
if td.path == "" {
panic("Couldn't create temporary directory: " + err.Error())
}
}
result := filepath.Join(td.path, strconv.Itoa(td.counter))
td.counter += 1
return result
}
func (td *tempDir) removeAll() {
td.Lock()
defer td.Unlock()
if td.path != "" {
err := os.RemoveAll(td.path)
if err != nil {
fmt.Fprintf(os.Stderr, "WARNING: Error cleaning up temporaries: "+err.Error())
}
}
}
// Create a new temporary directory which is automatically removed after
// the suite finishes running.
func (c *C) MkDir() string {
path := c.tempDir.newPath()
if err := os.Mkdir(path, 0700); err != nil {
panic(fmt.Sprintf("Couldn't create temporary directory %s: %s", path, err.Error()))
}
return path
}
// -----------------------------------------------------------------------
// Low-level logging functions.
func (c *C) log(args ...interface{}) {
c.writeLog([]byte(fmt.Sprint(args...) + "\n"))
}
func (c *C) logf(format string, args ...interface{}) {
c.writeLog([]byte(fmt.Sprintf(format+"\n", args...)))
}
func (c *C) logNewLine() {
c.writeLog([]byte{'\n'})
}
func (c *C) writeLog(buf []byte) {
c.logb.Write(buf)
if c.logw != nil {
c.logw.Write(buf)
}
}
func hasStringOrError(x interface{}) (ok bool) {
_, ok = x.(fmt.Stringer)
if ok {
return
}
_, ok = x.(error)
return
}
func (c *C) logValue(label string, value interface{}) {
if label == "" {
if hasStringOrError(value) {
c.logf("... %#v (%q)", value, value)
} else {
c.logf("... %#v", value)
}
} else if value == nil {
c.logf("... %s = nil", label)
} else {
if hasStringOrError(value) {
fv := fmt.Sprintf("%#v", value)
qv := fmt.Sprintf("%q", value)
if fv != qv {
c.logf("... %s %s = %s (%s)", label, reflect.TypeOf(value), fv, qv)
return
}
}
if s, ok := value.(string); ok && isMultiLine(s) {
c.logf(`... %s %s = "" +`, label, reflect.TypeOf(value))
c.logMultiLine(s)
} else {
c.logf("... %s %s = %#v", label, reflect.TypeOf(value), value)
}
}
}
func (c *C) logMultiLine(s string) {
b := make([]byte, 0, len(s)*2)
i := 0
n := len(s)
for i < n {
j := i + 1
for j < n && s[j-1] != '\n' {
j++
}
b = append(b, "... "...)
b = strconv.AppendQuote(b, s[i:j])
if j < n {
b = append(b, " +"...)
}
b = append(b, '\n')
i = j
}
c.writeLog(b)
}
func isMultiLine(s string) bool {
for i := 0; i+1 < len(s); i++ {
if s[i] == '\n' {
return true
}
}
return false
}
func (c *C) logString(issue string) {
c.log("... ", issue)
}
func (c *C) logCaller(skip int) {
// This is a bit heavier than it ought to be.
skip += 1 // Our own frame.
pc, callerFile, callerLine, ok := runtime.Caller(skip)
if !ok {
return
}
var testFile string
var testLine int
testFunc := runtime.FuncForPC(c.method.PC())
if runtime.FuncForPC(pc) != testFunc {
for {
skip += 1
if pc, file, line, ok := runtime.Caller(skip); ok {
// Note that the test line may be different on
// distinct calls for the same test. Showing
// the "internal" line is helpful when debugging.
if runtime.FuncForPC(pc) == testFunc {
testFile, testLine = file, line
break
}
} else {
break
}
}
}
if testFile != "" && (testFile != callerFile || testLine != callerLine) {
c.logCode(testFile, testLine)
}
c.logCode(callerFile, callerLine)
}
func (c *C) logCode(path string, line int) {
c.logf("%s:%d:", nicePath(path), line)
code, err := printLine(path, line)
if code == "" {
code = "..." // XXX Open the file and take the raw line.
if err != nil {
code += err.Error()
}
}
c.log(indent(code, " "))
}
var valueGo = filepath.Join("reflect", "value.go")
var asmGo = filepath.Join("runtime", "asm_")
func (c *C) logPanic(skip int, value interface{}) {
skip++ // Our own frame.
initialSkip := skip
for ; ; skip++ {
if pc, file, line, ok := runtime.Caller(skip); ok {
if skip == initialSkip {
c.logf("... Panic: %s (PC=0x%X)\n", value, pc)
}
name := niceFuncName(pc)
path := nicePath(file)
if strings.Contains(path, "/gopkg.in/check.v") {
continue
}
if name == "Value.call" && strings.HasSuffix(path, valueGo) {
continue
}
if name == "call16" && strings.Contains(path, asmGo) {
continue
}
c.logf("%s:%d\n in %s", nicePath(file), line, name)
} else {
break
}
}
}
func (c *C) logSoftPanic(issue string) {
c.log("... Panic: ", issue)
}
func (c *C) logArgPanic(method *methodType, expectedType string) {
c.logf("... Panic: %s argument should be %s",
niceFuncName(method.PC()), expectedType)
}
// -----------------------------------------------------------------------
// Some simple formatting helpers.
var initWD, initWDErr = os.Getwd()
func init() {
if initWDErr == nil {
initWD = strings.Replace(initWD, "\\", "/", -1) + "/"
}
}
func nicePath(path string) string {
if initWDErr == nil {
if strings.HasPrefix(path, initWD) {
return path[len(initWD):]
}
}
return path
}
func niceFuncPath(pc uintptr) string {
function := runtime.FuncForPC(pc)
if function != nil {
filename, line := function.FileLine(pc)
return fmt.Sprintf("%s:%d", nicePath(filename), line)
}
return "<unknown path>"
}
func niceFuncName(pc uintptr) string {
function := runtime.FuncForPC(pc)
if function != nil {
name := path.Base(function.Name())
if i := strings.Index(name, "."); i > 0 {
name = name[i+1:]
}
if strings.HasPrefix(name, "(*") {
if i := strings.Index(name, ")"); i > 0 {
name = name[2:i] + name[i+1:]
}
}
if i := strings.LastIndex(name, ".*"); i != -1 {
name = name[:i] + "." + name[i+2:]
}
if i := strings.LastIndex(name, "·"); i != -1 {
name = name[:i] + "." + name[i+2:]
}
return name
}
return "<unknown function>"
}
// -----------------------------------------------------------------------
// Result tracker to aggregate call results.
type Result struct {
Succeeded int
Failed int
Skipped int
Panicked int
FixturePanicked int
ExpectedFailures int
Missed int // Not even tried to run, related to a panic in the fixture.
RunError error // Houston, we've got a problem.
WorkDir string // If KeepWorkDir is true
}
type resultTracker struct {
result Result
_lastWasProblem bool
_waiting int
_missed int
_expectChan chan *C
_doneChan chan *C
_stopChan chan bool
}
func newResultTracker() *resultTracker {
return &resultTracker{_expectChan: make(chan *C), // Synchronous
_doneChan: make(chan *C, 32), // Asynchronous
_stopChan: make(chan bool)} // Synchronous
}
func (tracker *resultTracker) start() {
go tracker._loopRoutine()
}
func (tracker *resultTracker) waitAndStop() {
<-tracker._stopChan
}
func (tracker *resultTracker) expectCall(c *C) {
tracker._expectChan <- c
}
func (tracker *resultTracker) callDone(c *C) {
tracker._doneChan <- c
}
func (tracker *resultTracker) _loopRoutine() {
for {
var c *C
if tracker._waiting > 0 {
// Calls still running. Can't stop.
select {
// XXX Reindent this (not now to make diff clear)
case c = <-tracker._expectChan:
tracker._waiting += 1
case c = <-tracker._doneChan:
tracker._waiting -= 1
switch c.status {
case succeededSt:
if c.kind == testKd {
if c.mustFail {
tracker.result.ExpectedFailures++
} else {
tracker.result.Succeeded++
}
}
case failedSt:
tracker.result.Failed++
case panickedSt:
if c.kind == fixtureKd {
tracker.result.FixturePanicked++
} else {
tracker.result.Panicked++
}
case fixturePanickedSt:
// Track it as missed, since the panic
// was on the fixture, not on the test.
tracker.result.Missed++
case missedSt:
tracker.result.Missed++
case skippedSt:
if c.kind == testKd {
tracker.result.Skipped++
}
}
}
} else {
// No calls. Can stop, but no done calls here.
select {
case tracker._stopChan <- true:
return
case c = <-tracker._expectChan:
tracker._waiting += 1
case c = <-tracker._doneChan:
panic("Tracker got an unexpected done call.")
}
}
}
}
// -----------------------------------------------------------------------
// The underlying suite runner.
type suiteRunner struct {
suite interface{}
setUpSuite, tearDownSuite *methodType
setUpTest, tearDownTest *methodType
tests []*methodType
tracker *resultTracker
tempDir *tempDir
keepDir bool
output *outputWriter
reportedProblemLast bool
benchTime time.Duration
benchMem bool
}
type RunConf struct {
Output io.Writer
Stream bool
Verbose bool
Filter string
Benchmark bool
BenchmarkTime time.Duration // Defaults to 1 second
BenchmarkMem bool
KeepWorkDir bool
}
// Create a new suiteRunner able to run all methods in the given suite.
func newSuiteRunner(suite interface{}, runConf *RunConf) *suiteRunner {
var conf RunConf
if runConf != nil {
conf = *runConf
}
if conf.Output == nil {
conf.Output = os.Stdout
}
if conf.Benchmark {
conf.Verbose = true
}
suiteType := reflect.TypeOf(suite)
suiteNumMethods := suiteType.NumMethod()
suiteValue := reflect.ValueOf(suite)
runner := &suiteRunner{
suite: suite,
output: newOutputWriter(conf.Output, conf.Stream, conf.Verbose),
tracker: newResultTracker(),
benchTime: conf.BenchmarkTime,
benchMem: conf.BenchmarkMem,
tempDir: &tempDir{},
keepDir: conf.KeepWorkDir,
tests: make([]*methodType, 0, suiteNumMethods),
}
if runner.benchTime == 0 {
runner.benchTime = 1 * time.Second
}
var filterRegexp *regexp.Regexp
if conf.Filter != "" {
if regexp, err := regexp.Compile(conf.Filter); err != nil {
msg := "Bad filter expression: " + err.Error()
runner.tracker.result.RunError = errors.New(msg)
return runner
} else {
filterRegexp = regexp
}
}
for i := 0; i != suiteNumMethods; i++ {
method := newMethod(suiteValue, i)
switch method.Info.Name {
case "SetUpSuite":
runner.setUpSuite = method
case "TearDownSuite":
runner.tearDownSuite = method
case "SetUpTest":
runner.setUpTest = method
case "TearDownTest":
runner.tearDownTest = method
default:
prefix := "Test"
if conf.Benchmark {
prefix = "Benchmark"
}
if !strings.HasPrefix(method.Info.Name, prefix) {
continue
}
if filterRegexp == nil || method.matches(filterRegexp) {
runner.tests = append(runner.tests, method)
}
}
}
return runner
}
// Run all methods in the given suite.
func (runner *suiteRunner) run() *Result {
if runner.tracker.result.RunError == nil && len(runner.tests) > 0 {
runner.tracker.start()
if runner.checkFixtureArgs() {
c := runner.runFixture(runner.setUpSuite, "", nil)
if c == nil || c.status == succeededSt {
for i := 0; i != len(runner.tests); i++ {
c := runner.runTest(runner.tests[i])
if c.status == fixturePanickedSt {
runner.skipTests(missedSt, runner.tests[i+1:])
break
}
}
} else if c != nil && c.status == skippedSt {
runner.skipTests(skippedSt, runner.tests)
} else {
runner.skipTests(missedSt, runner.tests)
}
runner.runFixture(runner.tearDownSuite, "", nil)
} else {
runner.skipTests(missedSt, runner.tests)
}
runner.tracker.waitAndStop()
if runner.keepDir {
runner.tracker.result.WorkDir = runner.tempDir.path
} else {
runner.tempDir.removeAll()
}
}
return &runner.tracker.result
}
// Create a call object with the given suite method, and fork a
// goroutine with the provided dispatcher for running it.
func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C {
var logw io.Writer
if runner.output.Stream {
logw = runner.output
}
if logb == nil {
logb = new(logger)
}
c := &C{
method: method,
kind: kind,
testName: testName,
logb: logb,
logw: logw,
tempDir: runner.tempDir,
done: make(chan *C, 1),
timer: timer{benchTime: runner.benchTime},
startTime: time.Now(),
benchMem: runner.benchMem,
}
runner.tracker.expectCall(c)
go (func() {
runner.reportCallStarted(c)
defer runner.callDone(c)
dispatcher(c)
})()
return c
}
// Same as forkCall(), but wait for call to finish before returning.
func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C {
c := runner.forkCall(method, kind, testName, logb, dispatcher)
<-c.done
return c
}
// Handle a finished call. If there were any panics, update the call status
// accordingly. Then, mark the call as done and report to the tracker.
func (runner *suiteRunner) callDone(c *C) {
value := recover()
if value != nil {
switch v := value.(type) {
case *fixturePanic:
if v.status == skippedSt {
c.status = skippedSt
} else {
c.logSoftPanic("Fixture has panicked (see related PANIC)")
c.status = fixturePanickedSt
}
default:
c.logPanic(1, value)
c.status = panickedSt
}
}
if c.mustFail {
switch c.status {
case failedSt:
c.status = succeededSt
case succeededSt:
c.status = failedSt
c.logString("Error: Test succeeded, but was expected to fail")
c.logString("Reason: " + c.reason)
}
}
runner.reportCallDone(c)
c.done <- c
}
// Runs a fixture call synchronously. The fixture will still be run in a
// goroutine like all suite methods, but this method will not return
// while the fixture goroutine is not done, because the fixture must be
// run in a desired order.
func (runner *suiteRunner) runFixture(method *methodType, testName string, logb *logger) *C {
if method != nil {
c := runner.runFunc(method, fixtureKd, testName, logb, func(c *C) {
c.ResetTimer()
c.StartTimer()
defer c.StopTimer()
c.method.Call([]reflect.Value{reflect.ValueOf(c)})
})
return c
}
return nil
}
// Run the fixture method with runFixture(), but panic with a fixturePanic{}
// in case the fixture method panics. This makes it easier to track the
// fixture panic together with other call panics within forkTest().
func (runner *suiteRunner) runFixtureWithPanic(method *methodType, testName string, logb *logger, skipped *bool) *C {
if skipped != nil && *skipped {
return nil
}
c := runner.runFixture(method, testName, logb)
if c != nil && c.status != succeededSt {
if skipped != nil {
*skipped = c.status == skippedSt
}
panic(&fixturePanic{c.status, method})
}
return c
}
type fixturePanic struct {
status funcStatus
method *methodType
}
// Run the suite test method, together with the test-specific fixture,
// asynchronously.
func (runner *suiteRunner) forkTest(method *methodType) *C {
testName := method.String()
return runner.forkCall(method, testKd, testName, nil, func(c *C) {
var skipped bool
defer runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, &skipped)
defer c.StopTimer()
benchN := 1
for {
runner.runFixtureWithPanic(runner.setUpTest, testName, c.logb, &skipped)
mt := c.method.Type()
if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
// Rather than a plain panic, provide a more helpful message when
// the argument type is incorrect.
c.status = panickedSt
c.logArgPanic(c.method, "*check.C")
return
}
if strings.HasPrefix(c.method.Info.Name, "Test") {
c.ResetTimer()
c.StartTimer()
c.method.Call([]reflect.Value{reflect.ValueOf(c)})
return
}
if !strings.HasPrefix(c.method.Info.Name, "Benchmark") {
panic("unexpected method prefix: " + c.method.Info.Name)
}
runtime.GC()
c.N = benchN
c.ResetTimer()
c.StartTimer()
c.method.Call([]reflect.Value{reflect.ValueOf(c)})
c.StopTimer()
if c.status != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
return
}
perOpN := int(1e9)
if c.nsPerOp() != 0 {
perOpN = int(c.benchTime.Nanoseconds() / c.nsPerOp())
}
// Logic taken from the stock testing package:
// - Run more iterations than we think we'll need for a second (1.5x).
// - Don't grow too fast in case we had timing errors previously.
// - Be sure to run at least one more than last time.
benchN = max(min(perOpN+perOpN/2, 100*benchN), benchN+1)
benchN = roundUp(benchN)
skipped = true // Don't run the deferred one if this panics.
runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, nil)
skipped = false
}
})
}
// Same as forkTest(), but wait for the test to finish before returning.
func (runner *suiteRunner) runTest(method *methodType) *C {
c := runner.forkTest(method)
<-c.done
return c
}
// Helper to mark tests as skipped or missed. A bit heavy for what
// it does, but it enables homogeneous handling of tracking, including
// nice verbose output.
func (runner *suiteRunner) skipTests(status funcStatus, methods []*methodType) {
for _, method := range methods {
runner.runFunc(method, testKd, "", nil, func(c *C) {
c.status = status
})
}
}
// Verify if the fixture arguments are *check.C. In case of errors,
// log the error as a panic in the fixture method call, and return false.
func (runner *suiteRunner) checkFixtureArgs() bool {
succeeded := true
argType := reflect.TypeOf(&C{})
for _, method := range []*methodType{runner.setUpSuite, runner.tearDownSuite, runner.setUpTest, runner.tearDownTest} {
if method != nil {
mt := method.Type()
if mt.NumIn() != 1 || mt.In(0) != argType {
succeeded = false
runner.runFunc(method, fixtureKd, "", nil, func(c *C) {
c.logArgPanic(method, "*check.C")
c.status = panickedSt
})
}
}
}
return succeeded
}
func (runner *suiteRunner) reportCallStarted(c *C) {
runner.output.WriteCallStarted("START", c)
}
func (runner *suiteRunner) reportCallDone(c *C) {
runner.tracker.callDone(c)
switch c.status {
case succeededSt:
if c.mustFail {
runner.output.WriteCallSuccess("FAIL EXPECTED", c)
} else {
runner.output.WriteCallSuccess("PASS", c)
}
case skippedSt:
runner.output.WriteCallSuccess("SKIP", c)
case failedSt:
runner.output.WriteCallProblem("FAIL", c)
case panickedSt:
runner.output.WriteCallProblem("PANIC", c)
case fixturePanickedSt:
// That's a testKd call reporting that its fixture
// has panicked. The fixture call which caused the
// panic itself was tracked above. We'll report to
// aid debugging.
runner.output.WriteCallProblem("PANIC", c)
case missedSt:
runner.output.WriteCallSuccess("MISS", c)
}
}
// -----------------------------------------------------------------------
// Output writer manages atomic output writing according to settings.
type outputWriter struct {
m sync.Mutex
writer io.Writer
wroteCallProblemLast bool
Stream bool
Verbose bool
}
func newOutputWriter(writer io.Writer, stream, verbose bool) *outputWriter {
return &outputWriter{writer: writer, Stream: stream, Verbose: verbose}
}
func (ow *outputWriter) Write(content []byte) (n int, err error) {
ow.m.Lock()
n, err = ow.writer.Write(content)
ow.m.Unlock()
return
}
func (ow *outputWriter) WriteCallStarted(label string, c *C) {
if ow.Stream {
header := renderCallHeader(label, c, "", "\n")
ow.m.Lock()
ow.writer.Write([]byte(header))
ow.m.Unlock()
}
}
func (ow *outputWriter) WriteCallProblem(label string, c *C) {
var prefix string
if !ow.Stream {
prefix = "\n-----------------------------------" +
"-----------------------------------\n"
}
header := renderCallHeader(label, c, prefix, "\n\n")
ow.m.Lock()
ow.wroteCallProblemLast = true
ow.writer.Write([]byte(header))
if !ow.Stream {
c.logb.WriteTo(ow.writer)
}
ow.m.Unlock()
}
func (ow *outputWriter) WriteCallSuccess(label string, c *C) {
if ow.Stream || (ow.Verbose && c.kind == testKd) {
// TODO Use a buffer here.
var suffix string
if c.reason != "" {
suffix = " (" + c.reason + ")"
}
if c.status == succeededSt {
suffix += "\t" + c.timerString()
}
suffix += "\n"
if ow.Stream {
suffix += "\n"
}
header := renderCallHeader(label, c, "", suffix)
ow.m.Lock()
// Resist temptation of using line as prefix above due to race.
if !ow.Stream && ow.wroteCallProblemLast {
header = "\n-----------------------------------" +
"-----------------------------------\n" +
header
}
ow.wroteCallProblemLast = false
ow.writer.Write([]byte(header))
ow.m.Unlock()
}
}
func renderCallHeader(label string, c *C, prefix, suffix string) string {
pc := c.method.PC()
return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc),
niceFuncName(pc), suffix)
}
+207
View File
@@ -0,0 +1,207 @@
// This file contains just a few generic helpers which are used by the
// other test files.
package check_test
import (
"flag"
"fmt"
"os"
"regexp"
"runtime"
"testing"
"time"
"github.com/minio/check"
)
// We count the number of suites run at least to get a vague hint that the
// test suite is behaving as it should. Otherwise a bug introduced at the
// very core of the system could go unperceived.
const suitesRunExpected = 8
var suitesRun int = 0
func Test(t *testing.T) {
check.TestingT(t)
if suitesRun != suitesRunExpected && flag.Lookup("check.f").Value.String() == "" {
critical(fmt.Sprintf("Expected %d suites to run rather than %d",
suitesRunExpected, suitesRun))
}
}
// -----------------------------------------------------------------------
// Helper functions.
// Break down badly. This is used in test cases which can't yet assume
// that the fundamental bits are working.
func critical(error string) {
fmt.Fprintln(os.Stderr, "CRITICAL: "+error)
os.Exit(1)
}
// Return the file line where it's called.
func getMyLine() int {
if _, _, line, ok := runtime.Caller(1); ok {
return line
}
return -1
}
// -----------------------------------------------------------------------
// Helper type implementing a basic io.Writer for testing output.
// Type implementing the io.Writer interface for analyzing output.
type String struct {
value string
}
// The only function required by the io.Writer interface. Will append
// written data to the String.value string.
func (s *String) Write(p []byte) (n int, err error) {
s.value += string(p)
return len(p), nil
}
// Trivial wrapper to test errors happening on a different file
// than the test itself.
func checkEqualWrapper(c *check.C, obtained, expected interface{}) (result bool, line int) {
return c.Check(obtained, check.Equals, expected), getMyLine()
}
// -----------------------------------------------------------------------
// Helper suite for testing basic fail behavior.
type FailHelper struct {
testLine int
}
func (s *FailHelper) TestLogAndFail(c *check.C) {
s.testLine = getMyLine() - 1
c.Log("Expected failure!")
c.Fail()
}
// -----------------------------------------------------------------------
// Helper suite for testing basic success behavior.
type SuccessHelper struct{}
func (s *SuccessHelper) TestLogAndSucceed(c *check.C) {
c.Log("Expected success!")
}
// -----------------------------------------------------------------------
// Helper suite for testing ordering and behavior of fixture.
type FixtureHelper struct {
calls []string
panicOn string
skip bool
skipOnN int
sleepOn string
sleep time.Duration
bytes int64
}
func (s *FixtureHelper) trace(name string, c *check.C) {
s.calls = append(s.calls, name)
if name == s.panicOn {
panic(name)
}
if s.sleep > 0 && s.sleepOn == name {
time.Sleep(s.sleep)
}
if s.skip && s.skipOnN == len(s.calls)-1 {
c.Skip("skipOnN == n")
}
}
func (s *FixtureHelper) SetUpSuite(c *check.C) {
s.trace("SetUpSuite", c)
}
func (s *FixtureHelper) TearDownSuite(c *check.C) {
s.trace("TearDownSuite", c)
}
func (s *FixtureHelper) SetUpTest(c *check.C) {
s.trace("SetUpTest", c)
}
func (s *FixtureHelper) TearDownTest(c *check.C) {
s.trace("TearDownTest", c)
}
func (s *FixtureHelper) Test1(c *check.C) {
s.trace("Test1", c)
}
func (s *FixtureHelper) Test2(c *check.C) {
s.trace("Test2", c)
}
func (s *FixtureHelper) Benchmark1(c *check.C) {
s.trace("Benchmark1", c)
for i := 0; i < c.N; i++ {
time.Sleep(s.sleep)
}
}
func (s *FixtureHelper) Benchmark2(c *check.C) {
s.trace("Benchmark2", c)
c.SetBytes(1024)
for i := 0; i < c.N; i++ {
time.Sleep(s.sleep)
}
}
func (s *FixtureHelper) Benchmark3(c *check.C) {
var x []int64
s.trace("Benchmark3", c)
for i := 0; i < c.N; i++ {
time.Sleep(s.sleep)
x = make([]int64, 5)
_ = x
}
}
// -----------------------------------------------------------------------
// Helper which checks the state of the test and ensures that it matches
// the given expectations. Depends on c.Errorf() working, so shouldn't
// be used to test this one function.
type expectedState struct {
name string
result interface{}
failed bool
log string
}
// Verify the state of the test. Note that since this also verifies if
// the test is supposed to be in a failed state, no other checks should
// be done in addition to what is being tested.
func checkState(c *check.C, result interface{}, expected *expectedState) {
failed := c.Failed()
c.Succeed()
log := c.GetTestLog()
matched, matchError := regexp.MatchString("^"+expected.log+"$", log)
if matchError != nil {
c.Errorf("Error in matching expression used in testing %s",
expected.name)
} else if !matched {
c.Errorf("%s logged:\n----------\n%s----------\n\nExpected:\n----------\n%s\n----------",
expected.name, log, expected.log)
}
if result != expected.result {
c.Errorf("%s returned %#v rather than %#v",
expected.name, result, expected.result)
}
if failed != expected.failed {
if failed {
c.Errorf("%s has failed when it shouldn't", expected.name)
} else {
c.Errorf("%s has not failed when it should", expected.name)
}
}
}
+458
View File
@@ -0,0 +1,458 @@
package check
import (
"fmt"
"reflect"
"regexp"
)
// -----------------------------------------------------------------------
// CommentInterface and Commentf helper, to attach extra information to checks.
type comment struct {
format string
args []interface{}
}
// Commentf returns an infomational value to use with Assert or Check calls.
// If the checker test fails, the provided arguments will be passed to
// fmt.Sprintf, and will be presented next to the logged failure.
//
// For example:
//
// c.Assert(v, Equals, 42, Commentf("Iteration #%d failed.", i))
//
// Note that if the comment is constant, a better option is to
// simply use a normal comment right above or next to the line, as
// it will also get printed with any errors:
//
// c.Assert(l, Equals, 8192) // Ensure buffer size is correct (bug #123)
//
func Commentf(format string, args ...interface{}) CommentInterface {
return &comment{format, args}
}
// CommentInterface must be implemented by types that attach extra
// information to failed checks. See the Commentf function for details.
type CommentInterface interface {
CheckCommentString() string
}
func (c *comment) CheckCommentString() string {
return fmt.Sprintf(c.format, c.args...)
}
// -----------------------------------------------------------------------
// The Checker interface.
// The Checker interface must be provided by checkers used with
// the Assert and Check verification methods.
type Checker interface {
Info() *CheckerInfo
Check(params []interface{}, names []string) (result bool, error string)
}
// See the Checker interface.
type CheckerInfo struct {
Name string
Params []string
}
func (info *CheckerInfo) Info() *CheckerInfo {
return info
}
// -----------------------------------------------------------------------
// Not checker logic inverter.
// The Not checker inverts the logic of the provided checker. The
// resulting checker will succeed where the original one failed, and
// vice-versa.
//
// For example:
//
// c.Assert(a, Not(Equals), b)
//
func Not(checker Checker) Checker {
return &notChecker{checker}
}
type notChecker struct {
sub Checker
}
func (checker *notChecker) Info() *CheckerInfo {
info := *checker.sub.Info()
info.Name = "Not(" + info.Name + ")"
return &info
}
func (checker *notChecker) Check(params []interface{}, names []string) (result bool, error string) {
result, error = checker.sub.Check(params, names)
result = !result
return
}
// -----------------------------------------------------------------------
// IsNil checker.
type isNilChecker struct {
*CheckerInfo
}
// The IsNil checker tests whether the obtained value is nil.
//
// For example:
//
// c.Assert(err, IsNil)
//
var IsNil Checker = &isNilChecker{
&CheckerInfo{Name: "IsNil", Params: []string{"value"}},
}
func (checker *isNilChecker) Check(params []interface{}, names []string) (result bool, error string) {
return isNil(params[0]), ""
}
func isNil(obtained interface{}) (result bool) {
if obtained == nil {
result = true
} else {
switch v := reflect.ValueOf(obtained); v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return v.IsNil()
}
}
return
}
// -----------------------------------------------------------------------
// NotNil checker. Alias for Not(IsNil), since it's so common.
type notNilChecker struct {
*CheckerInfo
}
// The NotNil checker verifies that the obtained value is not nil.
//
// For example:
//
// c.Assert(iface, NotNil)
//
// This is an alias for Not(IsNil), made available since it's a
// fairly common check.
//
var NotNil Checker = &notNilChecker{
&CheckerInfo{Name: "NotNil", Params: []string{"value"}},
}
func (checker *notNilChecker) Check(params []interface{}, names []string) (result bool, error string) {
return !isNil(params[0]), ""
}
// -----------------------------------------------------------------------
// Equals checker.
type equalsChecker struct {
*CheckerInfo
}
// The Equals checker verifies that the obtained value is equal to
// the expected value, according to usual Go semantics for ==.
//
// For example:
//
// c.Assert(value, Equals, 42)
//
var Equals Checker = &equalsChecker{
&CheckerInfo{Name: "Equals", Params: []string{"obtained", "expected"}},
}
func (checker *equalsChecker) Check(params []interface{}, names []string) (result bool, error string) {
defer func() {
if v := recover(); v != nil {
result = false
error = fmt.Sprint(v)
}
}()
return params[0] == params[1], ""
}
// -----------------------------------------------------------------------
// DeepEquals checker.
type deepEqualsChecker struct {
*CheckerInfo
}
// The DeepEquals checker verifies that the obtained value is deep-equal to
// the expected value. The check will work correctly even when facing
// slices, interfaces, and values of different types (which always fail
// the test).
//
// For example:
//
// c.Assert(value, DeepEquals, 42)
// c.Assert(array, DeepEquals, []string{"hi", "there"})
//
var DeepEquals Checker = &deepEqualsChecker{
&CheckerInfo{Name: "DeepEquals", Params: []string{"obtained", "expected"}},
}
func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) {
return reflect.DeepEqual(params[0], params[1]), ""
}
// -----------------------------------------------------------------------
// HasLen checker.
type hasLenChecker struct {
*CheckerInfo
}
// The HasLen checker verifies that the obtained value has the
// provided length. In many cases this is superior to using Equals
// in conjuction with the len function because in case the check
// fails the value itself will be printed, instead of its length,
// providing more details for figuring the problem.
//
// For example:
//
// c.Assert(list, HasLen, 5)
//
var HasLen Checker = &hasLenChecker{
&CheckerInfo{Name: "HasLen", Params: []string{"obtained", "n"}},
}
func (checker *hasLenChecker) Check(params []interface{}, names []string) (result bool, error string) {
n, ok := params[1].(int)
if !ok {
return false, "n must be an int"
}
value := reflect.ValueOf(params[0])
switch value.Kind() {
case reflect.Map, reflect.Array, reflect.Slice, reflect.Chan, reflect.String:
default:
return false, "obtained value type has no length"
}
return value.Len() == n, ""
}
// -----------------------------------------------------------------------
// ErrorMatches checker.
type errorMatchesChecker struct {
*CheckerInfo
}
// The ErrorMatches checker verifies that the error value
// is non nil and matches the regular expression provided.
//
// For example:
//
// c.Assert(err, ErrorMatches, "perm.*denied")
//
var ErrorMatches Checker = errorMatchesChecker{
&CheckerInfo{Name: "ErrorMatches", Params: []string{"value", "regex"}},
}
func (checker errorMatchesChecker) Check(params []interface{}, names []string) (result bool, errStr string) {
if params[0] == nil {
return false, "Error value is nil"
}
err, ok := params[0].(error)
if !ok {
return false, "Value is not an error"
}
params[0] = err.Error()
names[0] = "error"
return matches(params[0], params[1])
}
// -----------------------------------------------------------------------
// Matches checker.
type matchesChecker struct {
*CheckerInfo
}
// The Matches checker verifies that the string provided as the obtained
// value (or the string resulting from obtained.String()) matches the
// regular expression provided.
//
// For example:
//
// c.Assert(err, Matches, "perm.*denied")
//
var Matches Checker = &matchesChecker{
&CheckerInfo{Name: "Matches", Params: []string{"value", "regex"}},
}
func (checker *matchesChecker) Check(params []interface{}, names []string) (result bool, error string) {
return matches(params[0], params[1])
}
func matches(value, regex interface{}) (result bool, error string) {
reStr, ok := regex.(string)
if !ok {
return false, "Regex must be a string"
}
valueStr, valueIsStr := value.(string)
if !valueIsStr {
if valueWithStr, valueHasStr := value.(fmt.Stringer); valueHasStr {
valueStr, valueIsStr = valueWithStr.String(), true
}
}
if valueIsStr {
matches, err := regexp.MatchString("^"+reStr+"$", valueStr)
if err != nil {
return false, "Can't compile regex: " + err.Error()
}
return matches, ""
}
return false, "Obtained value is not a string and has no .String()"
}
// -----------------------------------------------------------------------
// Panics checker.
type panicsChecker struct {
*CheckerInfo
}
// The Panics checker verifies that calling the provided zero-argument
// function will cause a panic which is deep-equal to the provided value.
//
// For example:
//
// c.Assert(func() { f(1, 2) }, Panics, &SomeErrorType{"BOOM"}).
//
//
var Panics Checker = &panicsChecker{
&CheckerInfo{Name: "Panics", Params: []string{"function", "expected"}},
}
func (checker *panicsChecker) Check(params []interface{}, names []string) (result bool, error string) {
f := reflect.ValueOf(params[0])
if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
return false, "Function must take zero arguments"
}
defer func() {
// If the function has not panicked, then don't do the check.
if error != "" {
return
}
params[0] = recover()
names[0] = "panic"
result = reflect.DeepEqual(params[0], params[1])
}()
f.Call(nil)
return false, "Function has not panicked"
}
type panicMatchesChecker struct {
*CheckerInfo
}
// The PanicMatches checker verifies that calling the provided zero-argument
// function will cause a panic with an error value matching
// the regular expression provided.
//
// For example:
//
// c.Assert(func() { f(1, 2) }, PanicMatches, `open.*: no such file or directory`).
//
//
var PanicMatches Checker = &panicMatchesChecker{
&CheckerInfo{Name: "PanicMatches", Params: []string{"function", "expected"}},
}
func (checker *panicMatchesChecker) Check(params []interface{}, names []string) (result bool, errmsg string) {
f := reflect.ValueOf(params[0])
if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
return false, "Function must take zero arguments"
}
defer func() {
// If the function has not panicked, then don't do the check.
if errmsg != "" {
return
}
obtained := recover()
names[0] = "panic"
if e, ok := obtained.(error); ok {
params[0] = e.Error()
} else if _, ok := obtained.(string); ok {
params[0] = obtained
} else {
errmsg = "Panic value is not a string or an error"
return
}
result, errmsg = matches(params[0], params[1])
}()
f.Call(nil)
return false, "Function has not panicked"
}
// -----------------------------------------------------------------------
// FitsTypeOf checker.
type fitsTypeChecker struct {
*CheckerInfo
}
// The FitsTypeOf checker verifies that the obtained value is
// assignable to a variable with the same type as the provided
// sample value.
//
// For example:
//
// c.Assert(value, FitsTypeOf, int64(0))
// c.Assert(value, FitsTypeOf, os.Error(nil))
//
var FitsTypeOf Checker = &fitsTypeChecker{
&CheckerInfo{Name: "FitsTypeOf", Params: []string{"obtained", "sample"}},
}
func (checker *fitsTypeChecker) Check(params []interface{}, names []string) (result bool, error string) {
obtained := reflect.ValueOf(params[0])
sample := reflect.ValueOf(params[1])
if !obtained.IsValid() {
return false, ""
}
if !sample.IsValid() {
return false, "Invalid sample value"
}
return obtained.Type().AssignableTo(sample.Type()), ""
}
// -----------------------------------------------------------------------
// Implements checker.
type implementsChecker struct {
*CheckerInfo
}
// The Implements checker verifies that the obtained value
// implements the interface specified via a pointer to an interface
// variable.
//
// For example:
//
// var e os.Error
// c.Assert(err, Implements, &e)
//
var Implements Checker = &implementsChecker{
&CheckerInfo{Name: "Implements", Params: []string{"obtained", "ifaceptr"}},
}
func (checker *implementsChecker) Check(params []interface{}, names []string) (result bool, error string) {
obtained := reflect.ValueOf(params[0])
ifaceptr := reflect.ValueOf(params[1])
if !obtained.IsValid() {
return false, ""
}
if !ifaceptr.IsValid() || ifaceptr.Kind() != reflect.Ptr || ifaceptr.Elem().Kind() != reflect.Interface {
return false, "ifaceptr should be a pointer to an interface variable"
}
return obtained.Type().Implements(ifaceptr.Elem().Type()), ""
}
+272
View File
@@ -0,0 +1,272 @@
package check_test
import (
"errors"
"github.com/minio/check"
"reflect"
"runtime"
)
type CheckersS struct{}
var _ = check.Suite(&CheckersS{})
func testInfo(c *check.C, checker check.Checker, name string, paramNames []string) {
info := checker.Info()
if info.Name != name {
c.Fatalf("Got name %s, expected %s", info.Name, name)
}
if !reflect.DeepEqual(info.Params, paramNames) {
c.Fatalf("Got param names %#v, expected %#v", info.Params, paramNames)
}
}
func testCheck(c *check.C, checker check.Checker, result bool, error string, params ...interface{}) ([]interface{}, []string) {
info := checker.Info()
if len(params) != len(info.Params) {
c.Fatalf("unexpected param count in test; expected %d got %d", len(info.Params), len(params))
}
names := append([]string{}, info.Params...)
result_, error_ := checker.Check(params, names)
if result_ != result || error_ != error {
c.Fatalf("%s.Check(%#v) returned (%#v, %#v) rather than (%#v, %#v)",
info.Name, params, result_, error_, result, error)
}
return params, names
}
func (s *CheckersS) TestComment(c *check.C) {
bug := check.Commentf("a %d bc", 42)
comment := bug.CheckCommentString()
if comment != "a 42 bc" {
c.Fatalf("Commentf returned %#v", comment)
}
}
func (s *CheckersS) TestIsNil(c *check.C) {
testInfo(c, check.IsNil, "IsNil", []string{"value"})
testCheck(c, check.IsNil, true, "", nil)
testCheck(c, check.IsNil, false, "", "a")
testCheck(c, check.IsNil, true, "", (chan int)(nil))
testCheck(c, check.IsNil, false, "", make(chan int))
testCheck(c, check.IsNil, true, "", (error)(nil))
testCheck(c, check.IsNil, false, "", errors.New(""))
testCheck(c, check.IsNil, true, "", ([]int)(nil))
testCheck(c, check.IsNil, false, "", make([]int, 1))
testCheck(c, check.IsNil, false, "", int(0))
}
func (s *CheckersS) TestNotNil(c *check.C) {
testInfo(c, check.NotNil, "NotNil", []string{"value"})
testCheck(c, check.NotNil, false, "", nil)
testCheck(c, check.NotNil, true, "", "a")
testCheck(c, check.NotNil, false, "", (chan int)(nil))
testCheck(c, check.NotNil, true, "", make(chan int))
testCheck(c, check.NotNil, false, "", (error)(nil))
testCheck(c, check.NotNil, true, "", errors.New(""))
testCheck(c, check.NotNil, false, "", ([]int)(nil))
testCheck(c, check.NotNil, true, "", make([]int, 1))
}
func (s *CheckersS) TestNot(c *check.C) {
testInfo(c, check.Not(check.IsNil), "Not(IsNil)", []string{"value"})
testCheck(c, check.Not(check.IsNil), false, "", nil)
testCheck(c, check.Not(check.IsNil), true, "", "a")
}
type simpleStruct struct {
i int
}
func (s *CheckersS) TestEquals(c *check.C) {
testInfo(c, check.Equals, "Equals", []string{"obtained", "expected"})
// The simplest.
testCheck(c, check.Equals, true, "", 42, 42)
testCheck(c, check.Equals, false, "", 42, 43)
// Different native types.
testCheck(c, check.Equals, false, "", int32(42), int64(42))
// With nil.
testCheck(c, check.Equals, false, "", 42, nil)
// Slices
testCheck(c, check.Equals, false, "runtime error: comparing uncomparable type []uint8", []byte{1, 2}, []byte{1, 2})
// Struct values
testCheck(c, check.Equals, true, "", simpleStruct{1}, simpleStruct{1})
testCheck(c, check.Equals, false, "", simpleStruct{1}, simpleStruct{2})
// Struct pointers
testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{1})
testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{2})
}
func (s *CheckersS) TestDeepEquals(c *check.C) {
testInfo(c, check.DeepEquals, "DeepEquals", []string{"obtained", "expected"})
// The simplest.
testCheck(c, check.DeepEquals, true, "", 42, 42)
testCheck(c, check.DeepEquals, false, "", 42, 43)
// Different native types.
testCheck(c, check.DeepEquals, false, "", int32(42), int64(42))
// With nil.
testCheck(c, check.DeepEquals, false, "", 42, nil)
// Slices
testCheck(c, check.DeepEquals, true, "", []byte{1, 2}, []byte{1, 2})
testCheck(c, check.DeepEquals, false, "", []byte{1, 2}, []byte{1, 3})
// Struct values
testCheck(c, check.DeepEquals, true, "", simpleStruct{1}, simpleStruct{1})
testCheck(c, check.DeepEquals, false, "", simpleStruct{1}, simpleStruct{2})
// Struct pointers
testCheck(c, check.DeepEquals, true, "", &simpleStruct{1}, &simpleStruct{1})
testCheck(c, check.DeepEquals, false, "", &simpleStruct{1}, &simpleStruct{2})
}
func (s *CheckersS) TestHasLen(c *check.C) {
testInfo(c, check.HasLen, "HasLen", []string{"obtained", "n"})
testCheck(c, check.HasLen, true, "", "abcd", 4)
testCheck(c, check.HasLen, true, "", []int{1, 2}, 2)
testCheck(c, check.HasLen, false, "", []int{1, 2}, 3)
testCheck(c, check.HasLen, false, "n must be an int", []int{1, 2}, "2")
testCheck(c, check.HasLen, false, "obtained value type has no length", nil, 2)
}
func (s *CheckersS) TestErrorMatches(c *check.C) {
testInfo(c, check.ErrorMatches, "ErrorMatches", []string{"value", "regex"})
testCheck(c, check.ErrorMatches, false, "Error value is nil", nil, "some error")
testCheck(c, check.ErrorMatches, false, "Value is not an error", 1, "some error")
testCheck(c, check.ErrorMatches, true, "", errors.New("some error"), "some error")
testCheck(c, check.ErrorMatches, true, "", errors.New("some error"), "so.*or")
// Verify params mutation
params, names := testCheck(c, check.ErrorMatches, false, "", errors.New("some error"), "other error")
c.Assert(params[0], check.Equals, "some error")
c.Assert(names[0], check.Equals, "error")
}
func (s *CheckersS) TestMatches(c *check.C) {
testInfo(c, check.Matches, "Matches", []string{"value", "regex"})
// Simple matching
testCheck(c, check.Matches, true, "", "abc", "abc")
testCheck(c, check.Matches, true, "", "abc", "a.c")
// Must match fully
testCheck(c, check.Matches, false, "", "abc", "ab")
testCheck(c, check.Matches, false, "", "abc", "bc")
// String()-enabled values accepted
testCheck(c, check.Matches, true, "", reflect.ValueOf("abc"), "a.c")
testCheck(c, check.Matches, false, "", reflect.ValueOf("abc"), "a.d")
// Some error conditions.
testCheck(c, check.Matches, false, "Obtained value is not a string and has no .String()", 1, "a.c")
testCheck(c, check.Matches, false, "Can't compile regex: error parsing regexp: missing closing ]: `[c$`", "abc", "a[c")
}
func (s *CheckersS) TestPanics(c *check.C) {
testInfo(c, check.Panics, "Panics", []string{"function", "expected"})
// Some errors.
testCheck(c, check.Panics, false, "Function has not panicked", func() bool { return false }, "BOOM")
testCheck(c, check.Panics, false, "Function must take zero arguments", 1, "BOOM")
// Plain strings.
testCheck(c, check.Panics, true, "", func() { panic("BOOM") }, "BOOM")
testCheck(c, check.Panics, false, "", func() { panic("KABOOM") }, "BOOM")
testCheck(c, check.Panics, true, "", func() bool { panic("BOOM") }, "BOOM")
// Error values.
testCheck(c, check.Panics, true, "", func() { panic(errors.New("BOOM")) }, errors.New("BOOM"))
testCheck(c, check.Panics, false, "", func() { panic(errors.New("KABOOM")) }, errors.New("BOOM"))
type deep struct{ i int }
// Deep value
testCheck(c, check.Panics, true, "", func() { panic(&deep{99}) }, &deep{99})
// Verify params/names mutation
params, names := testCheck(c, check.Panics, false, "", func() { panic(errors.New("KABOOM")) }, errors.New("BOOM"))
c.Assert(params[0], check.ErrorMatches, "KABOOM")
c.Assert(names[0], check.Equals, "panic")
// Verify a nil panic
testCheck(c, check.Panics, true, "", func() { panic(nil) }, nil)
testCheck(c, check.Panics, false, "", func() { panic(nil) }, "NOPE")
}
func (s *CheckersS) TestPanicMatches(c *check.C) {
testInfo(c, check.PanicMatches, "PanicMatches", []string{"function", "expected"})
// Error matching.
testCheck(c, check.PanicMatches, true, "", func() { panic(errors.New("BOOM")) }, "BO.M")
testCheck(c, check.PanicMatches, false, "", func() { panic(errors.New("KABOOM")) }, "BO.M")
// Some errors.
testCheck(c, check.PanicMatches, false, "Function has not panicked", func() bool { return false }, "BOOM")
testCheck(c, check.PanicMatches, false, "Function must take zero arguments", 1, "BOOM")
// Plain strings.
testCheck(c, check.PanicMatches, true, "", func() { panic("BOOM") }, "BO.M")
testCheck(c, check.PanicMatches, false, "", func() { panic("KABOOM") }, "BOOM")
testCheck(c, check.PanicMatches, true, "", func() bool { panic("BOOM") }, "BO.M")
// Verify params/names mutation
params, names := testCheck(c, check.PanicMatches, false, "", func() { panic(errors.New("KABOOM")) }, "BOOM")
c.Assert(params[0], check.Equals, "KABOOM")
c.Assert(names[0], check.Equals, "panic")
// Verify a nil panic
testCheck(c, check.PanicMatches, false, "Panic value is not a string or an error", func() { panic(nil) }, "")
}
func (s *CheckersS) TestFitsTypeOf(c *check.C) {
testInfo(c, check.FitsTypeOf, "FitsTypeOf", []string{"obtained", "sample"})
// Basic types
testCheck(c, check.FitsTypeOf, true, "", 1, 0)
testCheck(c, check.FitsTypeOf, false, "", 1, int64(0))
// Aliases
testCheck(c, check.FitsTypeOf, false, "", 1, errors.New(""))
testCheck(c, check.FitsTypeOf, false, "", "error", errors.New(""))
testCheck(c, check.FitsTypeOf, true, "", errors.New("error"), errors.New(""))
// Structures
testCheck(c, check.FitsTypeOf, false, "", 1, simpleStruct{})
testCheck(c, check.FitsTypeOf, false, "", simpleStruct{42}, &simpleStruct{})
testCheck(c, check.FitsTypeOf, true, "", simpleStruct{42}, simpleStruct{})
testCheck(c, check.FitsTypeOf, true, "", &simpleStruct{42}, &simpleStruct{})
// Some bad values
testCheck(c, check.FitsTypeOf, false, "Invalid sample value", 1, interface{}(nil))
testCheck(c, check.FitsTypeOf, false, "", interface{}(nil), 0)
}
func (s *CheckersS) TestImplements(c *check.C) {
testInfo(c, check.Implements, "Implements", []string{"obtained", "ifaceptr"})
var e error
var re runtime.Error
testCheck(c, check.Implements, true, "", errors.New(""), &e)
testCheck(c, check.Implements, false, "", errors.New(""), &re)
// Some bad values
testCheck(c, check.Implements, false, "ifaceptr should be a pointer to an interface variable", 0, errors.New(""))
testCheck(c, check.Implements, false, "ifaceptr should be a pointer to an interface variable", 0, interface{}(nil))
testCheck(c, check.Implements, false, "", interface{}(nil), &e)
}
+9
View File
@@ -0,0 +1,9 @@
package check
func PrintLine(filename string, line int) (string, error) {
return printLine(filename, line)
}
func Indent(s, with string) string {
return indent(s, with)
}
+484
View File
@@ -0,0 +1,484 @@
// Tests for the behavior of the test fixture system.
package check_test
import (
. "github.com/minio/check"
)
// -----------------------------------------------------------------------
// Fixture test suite.
type FixtureS struct{}
var fixtureS = Suite(&FixtureS{})
func (s *FixtureS) TestCountSuite(c *C) {
suitesRun += 1
}
// -----------------------------------------------------------------------
// Basic fixture ordering verification.
func (s *FixtureS) TestOrder(c *C) {
helper := FixtureHelper{}
Run(&helper, nil)
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "SetUpTest")
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 8)
}
// -----------------------------------------------------------------------
// Check the behavior when panics occur within tests and fixtures.
func (s *FixtureS) TestPanicOnTest(c *C) {
helper := FixtureHelper{panicOn: "Test1"}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "SetUpTest")
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 8)
expected := "^\n-+\n" +
"PANIC: check_test\\.go:[0-9]+: FixtureHelper.Test1\n\n" +
"\\.\\.\\. Panic: Test1 \\(PC=[xA-F0-9]+\\)\n\n" +
".+:[0-9]+\n" +
" in (go)?panic\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.trace\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.Test1\n" +
"(.|\n)*$"
c.Check(output.value, Matches, expected)
}
func (s *FixtureS) TestPanicOnSetUpTest(c *C) {
helper := FixtureHelper{panicOn: "SetUpTest"}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "TearDownTest")
c.Check(helper.calls[3], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 4)
expected := "^\n-+\n" +
"PANIC: check_test\\.go:[0-9]+: " +
"FixtureHelper\\.SetUpTest\n\n" +
"\\.\\.\\. Panic: SetUpTest \\(PC=[xA-F0-9]+\\)\n\n" +
".+:[0-9]+\n" +
" in (go)?panic\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.trace\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.SetUpTest\n" +
"(.|\n)*" +
"\n-+\n" +
"PANIC: check_test\\.go:[0-9]+: " +
"FixtureHelper\\.Test1\n\n" +
"\\.\\.\\. Panic: Fixture has panicked " +
"\\(see related PANIC\\)\n$"
c.Check(output.value, Matches, expected)
}
func (s *FixtureS) TestPanicOnTearDownTest(c *C) {
helper := FixtureHelper{panicOn: "TearDownTest"}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 5)
expected := "^\n-+\n" +
"PANIC: check_test\\.go:[0-9]+: " +
"FixtureHelper.TearDownTest\n\n" +
"\\.\\.\\. Panic: TearDownTest \\(PC=[xA-F0-9]+\\)\n\n" +
".+:[0-9]+\n" +
" in (go)?panic\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.trace\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.TearDownTest\n" +
"(.|\n)*" +
"\n-+\n" +
"PANIC: check_test\\.go:[0-9]+: " +
"FixtureHelper\\.Test1\n\n" +
"\\.\\.\\. Panic: Fixture has panicked " +
"\\(see related PANIC\\)\n$"
c.Check(output.value, Matches, expected)
}
func (s *FixtureS) TestPanicOnSetUpSuite(c *C) {
helper := FixtureHelper{panicOn: "SetUpSuite"}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 2)
expected := "^\n-+\n" +
"PANIC: check_test\\.go:[0-9]+: " +
"FixtureHelper.SetUpSuite\n\n" +
"\\.\\.\\. Panic: SetUpSuite \\(PC=[xA-F0-9]+\\)\n\n" +
".+:[0-9]+\n" +
" in (go)?panic\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.trace\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.SetUpSuite\n" +
"(.|\n)*$"
c.Check(output.value, Matches, expected)
}
func (s *FixtureS) TestPanicOnTearDownSuite(c *C) {
helper := FixtureHelper{panicOn: "TearDownSuite"}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "SetUpTest")
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 8)
expected := "^\n-+\n" +
"PANIC: check_test\\.go:[0-9]+: " +
"FixtureHelper.TearDownSuite\n\n" +
"\\.\\.\\. Panic: TearDownSuite \\(PC=[xA-F0-9]+\\)\n\n" +
".+:[0-9]+\n" +
" in (go)?panic\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.trace\n" +
".*check_test.go:[0-9]+\n" +
" in FixtureHelper.TearDownSuite\n" +
"(.|\n)*$"
c.Check(output.value, Matches, expected)
}
// -----------------------------------------------------------------------
// A wrong argument on a test or fixture will produce a nice error.
func (s *FixtureS) TestPanicOnWrongTestArg(c *C) {
helper := WrongTestArgHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "TearDownTest")
c.Check(helper.calls[3], Equals, "SetUpTest")
c.Check(helper.calls[4], Equals, "Test2")
c.Check(helper.calls[5], Equals, "TearDownTest")
c.Check(helper.calls[6], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 7)
expected := "^\n-+\n" +
"PANIC: fixture_test\\.go:[0-9]+: " +
"WrongTestArgHelper\\.Test1\n\n" +
"\\.\\.\\. Panic: WrongTestArgHelper\\.Test1 argument " +
"should be \\*check\\.C\n"
c.Check(output.value, Matches, expected)
}
func (s *FixtureS) TestPanicOnWrongSetUpTestArg(c *C) {
helper := WrongSetUpTestArgHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(len(helper.calls), Equals, 0)
expected :=
"^\n-+\n" +
"PANIC: fixture_test\\.go:[0-9]+: " +
"WrongSetUpTestArgHelper\\.SetUpTest\n\n" +
"\\.\\.\\. Panic: WrongSetUpTestArgHelper\\.SetUpTest argument " +
"should be \\*check\\.C\n"
c.Check(output.value, Matches, expected)
}
func (s *FixtureS) TestPanicOnWrongSetUpSuiteArg(c *C) {
helper := WrongSetUpSuiteArgHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(len(helper.calls), Equals, 0)
expected :=
"^\n-+\n" +
"PANIC: fixture_test\\.go:[0-9]+: " +
"WrongSetUpSuiteArgHelper\\.SetUpSuite\n\n" +
"\\.\\.\\. Panic: WrongSetUpSuiteArgHelper\\.SetUpSuite argument " +
"should be \\*check\\.C\n"
c.Check(output.value, Matches, expected)
}
// -----------------------------------------------------------------------
// Nice errors also when tests or fixture have wrong arg count.
func (s *FixtureS) TestPanicOnWrongTestArgCount(c *C) {
helper := WrongTestArgCountHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "TearDownTest")
c.Check(helper.calls[3], Equals, "SetUpTest")
c.Check(helper.calls[4], Equals, "Test2")
c.Check(helper.calls[5], Equals, "TearDownTest")
c.Check(helper.calls[6], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 7)
expected := "^\n-+\n" +
"PANIC: fixture_test\\.go:[0-9]+: " +
"WrongTestArgCountHelper\\.Test1\n\n" +
"\\.\\.\\. Panic: WrongTestArgCountHelper\\.Test1 argument " +
"should be \\*check\\.C\n"
c.Check(output.value, Matches, expected)
}
func (s *FixtureS) TestPanicOnWrongSetUpTestArgCount(c *C) {
helper := WrongSetUpTestArgCountHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(len(helper.calls), Equals, 0)
expected :=
"^\n-+\n" +
"PANIC: fixture_test\\.go:[0-9]+: " +
"WrongSetUpTestArgCountHelper\\.SetUpTest\n\n" +
"\\.\\.\\. Panic: WrongSetUpTestArgCountHelper\\.SetUpTest argument " +
"should be \\*check\\.C\n"
c.Check(output.value, Matches, expected)
}
func (s *FixtureS) TestPanicOnWrongSetUpSuiteArgCount(c *C) {
helper := WrongSetUpSuiteArgCountHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(len(helper.calls), Equals, 0)
expected :=
"^\n-+\n" +
"PANIC: fixture_test\\.go:[0-9]+: " +
"WrongSetUpSuiteArgCountHelper\\.SetUpSuite\n\n" +
"\\.\\.\\. Panic: WrongSetUpSuiteArgCountHelper" +
"\\.SetUpSuite argument should be \\*check\\.C\n"
c.Check(output.value, Matches, expected)
}
// -----------------------------------------------------------------------
// Helper test suites with wrong function arguments.
type WrongTestArgHelper struct {
FixtureHelper
}
func (s *WrongTestArgHelper) Test1(t int) {
}
type WrongSetUpTestArgHelper struct {
FixtureHelper
}
func (s *WrongSetUpTestArgHelper) SetUpTest(t int) {
}
type WrongSetUpSuiteArgHelper struct {
FixtureHelper
}
func (s *WrongSetUpSuiteArgHelper) SetUpSuite(t int) {
}
type WrongTestArgCountHelper struct {
FixtureHelper
}
func (s *WrongTestArgCountHelper) Test1(c *C, i int) {
}
type WrongSetUpTestArgCountHelper struct {
FixtureHelper
}
func (s *WrongSetUpTestArgCountHelper) SetUpTest(c *C, i int) {
}
type WrongSetUpSuiteArgCountHelper struct {
FixtureHelper
}
func (s *WrongSetUpSuiteArgCountHelper) SetUpSuite(c *C, i int) {
}
// -----------------------------------------------------------------------
// Ensure fixture doesn't run without tests.
type NoTestsHelper struct {
hasRun bool
}
func (s *NoTestsHelper) SetUpSuite(c *C) {
s.hasRun = true
}
func (s *NoTestsHelper) TearDownSuite(c *C) {
s.hasRun = true
}
func (s *FixtureS) TestFixtureDoesntRunWithoutTests(c *C) {
helper := NoTestsHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Check(helper.hasRun, Equals, false)
}
// -----------------------------------------------------------------------
// Verify that checks and assertions work correctly inside the fixture.
type FixtureCheckHelper struct {
fail string
completed bool
}
func (s *FixtureCheckHelper) SetUpSuite(c *C) {
switch s.fail {
case "SetUpSuiteAssert":
c.Assert(false, Equals, true)
case "SetUpSuiteCheck":
c.Check(false, Equals, true)
}
s.completed = true
}
func (s *FixtureCheckHelper) SetUpTest(c *C) {
switch s.fail {
case "SetUpTestAssert":
c.Assert(false, Equals, true)
case "SetUpTestCheck":
c.Check(false, Equals, true)
}
s.completed = true
}
func (s *FixtureCheckHelper) Test(c *C) {
// Do nothing.
}
func (s *FixtureS) TestSetUpSuiteCheck(c *C) {
helper := FixtureCheckHelper{fail: "SetUpSuiteCheck"}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Assert(output.value, Matches,
"\n---+\n"+
"FAIL: fixture_test\\.go:[0-9]+: "+
"FixtureCheckHelper\\.SetUpSuite\n\n"+
"fixture_test\\.go:[0-9]+:\n"+
" c\\.Check\\(false, Equals, true\\)\n"+
"\\.+ obtained bool = false\n"+
"\\.+ expected bool = true\n\n")
c.Assert(helper.completed, Equals, true)
}
func (s *FixtureS) TestSetUpSuiteAssert(c *C) {
helper := FixtureCheckHelper{fail: "SetUpSuiteAssert"}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Assert(output.value, Matches,
"\n---+\n"+
"FAIL: fixture_test\\.go:[0-9]+: "+
"FixtureCheckHelper\\.SetUpSuite\n\n"+
"fixture_test\\.go:[0-9]+:\n"+
" c\\.Assert\\(false, Equals, true\\)\n"+
"\\.+ obtained bool = false\n"+
"\\.+ expected bool = true\n\n")
c.Assert(helper.completed, Equals, false)
}
// -----------------------------------------------------------------------
// Verify that logging within SetUpTest() persists within the test log itself.
type FixtureLogHelper struct {
c *C
}
func (s *FixtureLogHelper) SetUpTest(c *C) {
s.c = c
c.Log("1")
}
func (s *FixtureLogHelper) Test(c *C) {
c.Log("2")
s.c.Log("3")
c.Log("4")
c.Fail()
}
func (s *FixtureLogHelper) TearDownTest(c *C) {
s.c.Log("5")
}
func (s *FixtureS) TestFixtureLogging(c *C) {
helper := FixtureLogHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Assert(output.value, Matches,
"\n---+\n"+
"FAIL: fixture_test\\.go:[0-9]+: "+
"FixtureLogHelper\\.Test\n\n"+
"1\n2\n3\n4\n5\n")
}
// -----------------------------------------------------------------------
// Skip() within fixture methods.
func (s *FixtureS) TestSkipSuite(c *C) {
helper := FixtureHelper{skip: true, skipOnN: 0}
output := String{}
result := Run(&helper, &RunConf{Output: &output})
c.Assert(output.value, Equals, "")
c.Assert(helper.calls[0], Equals, "SetUpSuite")
c.Assert(helper.calls[1], Equals, "TearDownSuite")
c.Assert(len(helper.calls), Equals, 2)
c.Assert(result.Skipped, Equals, 2)
}
func (s *FixtureS) TestSkipTest(c *C) {
helper := FixtureHelper{skip: true, skipOnN: 1}
output := String{}
result := Run(&helper, &RunConf{Output: &output})
c.Assert(helper.calls[0], Equals, "SetUpSuite")
c.Assert(helper.calls[1], Equals, "SetUpTest")
c.Assert(helper.calls[2], Equals, "SetUpTest")
c.Assert(helper.calls[3], Equals, "Test2")
c.Assert(helper.calls[4], Equals, "TearDownTest")
c.Assert(helper.calls[5], Equals, "TearDownSuite")
c.Assert(len(helper.calls), Equals, 6)
c.Assert(result.Skipped, Equals, 1)
}
+335
View File
@@ -0,0 +1,335 @@
// These tests check that the foundations of gocheck are working properly.
// They already assume that fundamental failing is working already, though,
// since this was tested in bootstrap_test.go. Even then, some care may
// still have to be taken when using external functions, since they should
// of course not rely on functionality tested here.
package check_test
import (
"fmt"
"github.com/minio/check"
"log"
"os"
"regexp"
"strings"
)
// -----------------------------------------------------------------------
// Foundation test suite.
type FoundationS struct{}
var foundationS = check.Suite(&FoundationS{})
func (s *FoundationS) TestCountSuite(c *check.C) {
suitesRun += 1
}
func (s *FoundationS) TestErrorf(c *check.C) {
// Do not use checkState() here. It depends on Errorf() working.
expectedLog := fmt.Sprintf("foundation_test.go:%d:\n"+
" c.Errorf(\"Error %%v!\", \"message\")\n"+
"... Error: Error message!\n\n",
getMyLine()+1)
c.Errorf("Error %v!", "message")
failed := c.Failed()
c.Succeed()
if log := c.GetTestLog(); log != expectedLog {
c.Logf("Errorf() logged %#v rather than %#v", log, expectedLog)
c.Fail()
}
if !failed {
c.Logf("Errorf() didn't put the test in a failed state")
c.Fail()
}
}
func (s *FoundationS) TestError(c *check.C) {
expectedLog := fmt.Sprintf("foundation_test.go:%d:\n"+
" c\\.Error\\(\"Error \", \"message!\"\\)\n"+
"\\.\\.\\. Error: Error message!\n\n",
getMyLine()+1)
c.Error("Error ", "message!")
checkState(c, nil,
&expectedState{
name: "Error(`Error `, `message!`)",
failed: true,
log: expectedLog,
})
}
func (s *FoundationS) TestFailNow(c *check.C) {
defer (func() {
if !c.Failed() {
c.Error("FailNow() didn't fail the test")
} else {
c.Succeed()
if c.GetTestLog() != "" {
c.Error("Something got logged:\n" + c.GetTestLog())
}
}
})()
c.FailNow()
c.Log("FailNow() didn't stop the test")
}
func (s *FoundationS) TestSucceedNow(c *check.C) {
defer (func() {
if c.Failed() {
c.Error("SucceedNow() didn't succeed the test")
}
if c.GetTestLog() != "" {
c.Error("Something got logged:\n" + c.GetTestLog())
}
})()
c.Fail()
c.SucceedNow()
c.Log("SucceedNow() didn't stop the test")
}
func (s *FoundationS) TestFailureHeader(c *check.C) {
output := String{}
failHelper := FailHelper{}
check.Run(&failHelper, &check.RunConf{Output: &output})
header := fmt.Sprintf(""+
"\n-----------------------------------"+
"-----------------------------------\n"+
"FAIL: check_test.go:%d: FailHelper.TestLogAndFail\n",
failHelper.testLine)
if strings.Index(output.value, header) == -1 {
c.Errorf(""+
"Failure didn't print a proper header.\n"+
"... Got:\n%s... Expected something with:\n%s",
output.value, header)
}
}
func (s *FoundationS) TestFatal(c *check.C) {
var line int
defer (func() {
if !c.Failed() {
c.Error("Fatal() didn't fail the test")
} else {
c.Succeed()
expected := fmt.Sprintf("foundation_test.go:%d:\n"+
" c.Fatal(\"Die \", \"now!\")\n"+
"... Error: Die now!\n\n",
line)
if c.GetTestLog() != expected {
c.Error("Incorrect log:", c.GetTestLog())
}
}
})()
line = getMyLine() + 1
c.Fatal("Die ", "now!")
c.Log("Fatal() didn't stop the test")
}
func (s *FoundationS) TestFatalf(c *check.C) {
var line int
defer (func() {
if !c.Failed() {
c.Error("Fatalf() didn't fail the test")
} else {
c.Succeed()
expected := fmt.Sprintf("foundation_test.go:%d:\n"+
" c.Fatalf(\"Die %%s!\", \"now\")\n"+
"... Error: Die now!\n\n",
line)
if c.GetTestLog() != expected {
c.Error("Incorrect log:", c.GetTestLog())
}
}
})()
line = getMyLine() + 1
c.Fatalf("Die %s!", "now")
c.Log("Fatalf() didn't stop the test")
}
func (s *FoundationS) TestCallerLoggingInsideTest(c *check.C) {
log := fmt.Sprintf(""+
"foundation_test.go:%d:\n"+
" result := c.Check\\(10, check.Equals, 20\\)\n"+
"\\.\\.\\. obtained int = 10\n"+
"\\.\\.\\. expected int = 20\n\n",
getMyLine()+1)
result := c.Check(10, check.Equals, 20)
checkState(c, result,
&expectedState{
name: "Check(10, Equals, 20)",
result: false,
failed: true,
log: log,
})
}
func (s *FoundationS) TestCallerLoggingInDifferentFile(c *check.C) {
result, line := checkEqualWrapper(c, 10, 20)
testLine := getMyLine() - 1
log := fmt.Sprintf(""+
"foundation_test.go:%d:\n"+
" result, line := checkEqualWrapper\\(c, 10, 20\\)\n"+
"check_test.go:%d:\n"+
" return c.Check\\(obtained, check.Equals, expected\\), getMyLine\\(\\)\n"+
"\\.\\.\\. obtained int = 10\n"+
"\\.\\.\\. expected int = 20\n\n",
testLine, line)
checkState(c, result,
&expectedState{
name: "Check(10, Equals, 20)",
result: false,
failed: true,
log: log,
})
}
// -----------------------------------------------------------------------
// ExpectFailure() inverts the logic of failure.
type ExpectFailureSucceedHelper struct{}
func (s *ExpectFailureSucceedHelper) TestSucceed(c *check.C) {
c.ExpectFailure("It booms!")
c.Error("Boom!")
}
type ExpectFailureFailHelper struct{}
func (s *ExpectFailureFailHelper) TestFail(c *check.C) {
c.ExpectFailure("Bug #XYZ")
}
func (s *FoundationS) TestExpectFailureFail(c *check.C) {
helper := ExpectFailureFailHelper{}
output := String{}
result := check.Run(&helper, &check.RunConf{Output: &output})
expected := "" +
"^\n-+\n" +
"FAIL: foundation_test\\.go:[0-9]+:" +
" ExpectFailureFailHelper\\.TestFail\n\n" +
"\\.\\.\\. Error: Test succeeded, but was expected to fail\n" +
"\\.\\.\\. Reason: Bug #XYZ\n$"
matched, err := regexp.MatchString(expected, output.value)
if err != nil {
c.Error("Bad expression: ", expected)
} else if !matched {
c.Error("ExpectFailure() didn't log properly:\n", output.value)
}
c.Assert(result.ExpectedFailures, check.Equals, 0)
}
func (s *FoundationS) TestExpectFailureSucceed(c *check.C) {
helper := ExpectFailureSucceedHelper{}
output := String{}
result := check.Run(&helper, &check.RunConf{Output: &output})
c.Assert(output.value, check.Equals, "")
c.Assert(result.ExpectedFailures, check.Equals, 1)
}
func (s *FoundationS) TestExpectFailureSucceedVerbose(c *check.C) {
helper := ExpectFailureSucceedHelper{}
output := String{}
result := check.Run(&helper, &check.RunConf{Output: &output, Verbose: true})
expected := "" +
"FAIL EXPECTED: foundation_test\\.go:[0-9]+:" +
" ExpectFailureSucceedHelper\\.TestSucceed \\(It booms!\\)\t *[.0-9]+s\n"
matched, err := regexp.MatchString(expected, output.value)
if err != nil {
c.Error("Bad expression: ", expected)
} else if !matched {
c.Error("ExpectFailure() didn't log properly:\n", output.value)
}
c.Assert(result.ExpectedFailures, check.Equals, 1)
}
// -----------------------------------------------------------------------
// Skip() allows stopping a test without positive/negative results.
type SkipTestHelper struct{}
func (s *SkipTestHelper) TestFail(c *check.C) {
c.Skip("Wrong platform or whatever")
c.Error("Boom!")
}
func (s *FoundationS) TestSkip(c *check.C) {
helper := SkipTestHelper{}
output := String{}
check.Run(&helper, &check.RunConf{Output: &output})
if output.value != "" {
c.Error("Skip() logged something:\n", output.value)
}
}
func (s *FoundationS) TestSkipVerbose(c *check.C) {
helper := SkipTestHelper{}
output := String{}
check.Run(&helper, &check.RunConf{Output: &output, Verbose: true})
expected := "SKIP: foundation_test\\.go:[0-9]+: SkipTestHelper\\.TestFail" +
" \\(Wrong platform or whatever\\)"
matched, err := regexp.MatchString(expected, output.value)
if err != nil {
c.Error("Bad expression: ", expected)
} else if !matched {
c.Error("Skip() didn't log properly:\n", output.value)
}
}
// -----------------------------------------------------------------------
// Check minimum *log.Logger interface provided by *check.C.
type minLogger interface {
Output(calldepth int, s string) error
}
func (s *BootstrapS) TestMinLogger(c *check.C) {
var logger minLogger
logger = log.New(os.Stderr, "", 0)
logger = c
logger.Output(0, "Hello there")
expected := `\[LOG\] [0-9]+:[0-9][0-9]\.[0-9][0-9][0-9] +Hello there\n`
output := c.GetTestLog()
c.Assert(output, check.Matches, expected)
}
// -----------------------------------------------------------------------
// Ensure that suites with embedded types are working fine, including the
// the workaround for issue 906.
type EmbeddedInternalS struct {
called bool
}
type EmbeddedS struct {
EmbeddedInternalS
}
var embeddedS = check.Suite(&EmbeddedS{})
func (s *EmbeddedS) TestCountSuite(c *check.C) {
suitesRun += 1
}
func (s *EmbeddedInternalS) TestMethod(c *check.C) {
c.Error("TestMethod() of the embedded type was called!?")
}
func (s *EmbeddedS) TestMethod(c *check.C) {
// http://code.google.com/p/go/issues/detail?id=906
c.Check(s.called, check.Equals, false) // Go issue 906 is affecting the runner?
s.called = true
}
+231
View File
@@ -0,0 +1,231 @@
package check
import (
"fmt"
"strings"
"time"
)
// TestName returns the current test name in the form "SuiteName.TestName"
func (c *C) TestName() string {
return c.testName
}
// -----------------------------------------------------------------------
// Basic succeeding/failing logic.
// Failed returns whether the currently running test has already failed.
func (c *C) Failed() bool {
return c.status == failedSt
}
// Fail marks the currently running test as failed.
//
// Something ought to have been previously logged so the developer can tell
// what went wrong. The higher level helper functions will fail the test
// and do the logging properly.
func (c *C) Fail() {
c.status = failedSt
}
// FailNow marks the currently running test as failed and stops running it.
// Something ought to have been previously logged so the developer can tell
// what went wrong. The higher level helper functions will fail the test
// and do the logging properly.
func (c *C) FailNow() {
c.Fail()
c.stopNow()
}
// Succeed marks the currently running test as succeeded, undoing any
// previous failures.
func (c *C) Succeed() {
c.status = succeededSt
}
// SucceedNow marks the currently running test as succeeded, undoing any
// previous failures, and stops running the test.
func (c *C) SucceedNow() {
c.Succeed()
c.stopNow()
}
// ExpectFailure informs that the running test is knowingly broken for
// the provided reason. If the test does not fail, an error will be reported
// to raise attention to this fact. This method is useful to temporarily
// disable tests which cover well known problems until a better time to
// fix the problem is found, without forgetting about the fact that a
// failure still exists.
func (c *C) ExpectFailure(reason string) {
if reason == "" {
panic("Missing reason why the test is expected to fail")
}
c.mustFail = true
c.reason = reason
}
// Skip skips the running test for the provided reason. If run from within
// SetUpTest, the individual test being set up will be skipped, and if run
// from within SetUpSuite, the whole suite is skipped.
func (c *C) Skip(reason string) {
if reason == "" {
panic("Missing reason why the test is being skipped")
}
c.reason = reason
c.status = skippedSt
c.stopNow()
}
// -----------------------------------------------------------------------
// Basic logging.
// GetTestLog returns the current test error output.
func (c *C) GetTestLog() string {
return c.logb.String()
}
// Log logs some information into the test error output.
// The provided arguments are assembled together into a string with fmt.Sprint.
func (c *C) Log(args ...interface{}) {
c.log(args...)
}
// Log logs some information into the test error output.
// The provided arguments are assembled together into a string with fmt.Sprintf.
func (c *C) Logf(format string, args ...interface{}) {
c.logf(format, args...)
}
// Output enables *C to be used as a logger in functions that require only
// the minimum interface of *log.Logger.
func (c *C) Output(calldepth int, s string) error {
d := time.Now().Sub(c.startTime)
msec := d / time.Millisecond
sec := d / time.Second
min := d / time.Minute
c.Logf("[LOG] %d:%02d.%03d %s", min, sec%60, msec%1000, s)
return nil
}
// Error logs an error into the test error output and marks the test as failed.
// The provided arguments are assembled together into a string with fmt.Sprint.
func (c *C) Error(args ...interface{}) {
c.logCaller(1)
c.logString(fmt.Sprint("Error: ", fmt.Sprint(args...)))
c.logNewLine()
c.Fail()
}
// Errorf logs an error into the test error output and marks the test as failed.
// The provided arguments are assembled together into a string with fmt.Sprintf.
func (c *C) Errorf(format string, args ...interface{}) {
c.logCaller(1)
c.logString(fmt.Sprintf("Error: "+format, args...))
c.logNewLine()
c.Fail()
}
// Fatal logs an error into the test error output, marks the test as failed, and
// stops the test execution. The provided arguments are assembled together into
// a string with fmt.Sprint.
func (c *C) Fatal(args ...interface{}) {
c.logCaller(1)
c.logString(fmt.Sprint("Error: ", fmt.Sprint(args...)))
c.logNewLine()
c.FailNow()
}
// Fatlaf logs an error into the test error output, marks the test as failed, and
// stops the test execution. The provided arguments are assembled together into
// a string with fmt.Sprintf.
func (c *C) Fatalf(format string, args ...interface{}) {
c.logCaller(1)
c.logString(fmt.Sprint("Error: ", fmt.Sprintf(format, args...)))
c.logNewLine()
c.FailNow()
}
// -----------------------------------------------------------------------
// Generic checks and assertions based on checkers.
// Check verifies if the first value matches the expected value according
// to the provided checker. If they do not match, an error is logged, the
// test is marked as failed, and the test execution continues.
//
// Some checkers may not need the expected argument (e.g. IsNil).
//
// Extra arguments provided to the function are logged next to the reported
// problem when the matching fails.
func (c *C) Check(obtained interface{}, checker Checker, args ...interface{}) bool {
return c.internalCheck("Check", obtained, checker, args...)
}
// Assert ensures that the first value matches the expected value according
// to the provided checker. If they do not match, an error is logged, the
// test is marked as failed, and the test execution stops.
//
// Some checkers may not need the expected argument (e.g. IsNil).
//
// Extra arguments provided to the function are logged next to the reported
// problem when the matching fails.
func (c *C) Assert(obtained interface{}, checker Checker, args ...interface{}) {
if !c.internalCheck("Assert", obtained, checker, args...) {
c.stopNow()
}
}
func (c *C) internalCheck(funcName string, obtained interface{}, checker Checker, args ...interface{}) bool {
if checker == nil {
c.logCaller(2)
c.logString(fmt.Sprintf("%s(obtained, nil!?, ...):", funcName))
c.logString("Oops.. you've provided a nil checker!")
c.logNewLine()
c.Fail()
return false
}
// If the last argument is a bug info, extract it out.
var comment CommentInterface
if len(args) > 0 {
if c, ok := args[len(args)-1].(CommentInterface); ok {
comment = c
args = args[:len(args)-1]
}
}
params := append([]interface{}{obtained}, args...)
info := checker.Info()
if len(params) != len(info.Params) {
names := append([]string{info.Params[0], info.Name}, info.Params[1:]...)
c.logCaller(2)
c.logString(fmt.Sprintf("%s(%s):", funcName, strings.Join(names, ", ")))
c.logString(fmt.Sprintf("Wrong number of parameters for %s: want %d, got %d", info.Name, len(names), len(params)+1))
c.logNewLine()
c.Fail()
return false
}
// Copy since it may be mutated by Check.
names := append([]string{}, info.Params...)
// Do the actual check.
result, error := checker.Check(params, names)
if !result || error != "" {
c.logCaller(2)
for i := 0; i != len(params); i++ {
c.logValue(names[i], params[i])
}
if comment != nil {
c.logString(comment.CheckCommentString())
}
if error != "" {
c.logString(error)
}
c.logNewLine()
c.Fail()
return false
}
return true
}
+519
View File
@@ -0,0 +1,519 @@
// These tests verify the inner workings of the helper methods associated
// with check.T.
package check_test
import (
"github.com/minio/check"
"os"
"reflect"
"runtime"
"sync"
)
var helpersS = check.Suite(&HelpersS{})
type HelpersS struct{}
func (s *HelpersS) TestCountSuite(c *check.C) {
suitesRun += 1
}
// -----------------------------------------------------------------------
// Fake checker and bug info to verify the behavior of Assert() and Check().
type MyChecker struct {
info *check.CheckerInfo
params []interface{}
names []string
result bool
error string
}
func (checker *MyChecker) Info() *check.CheckerInfo {
if checker.info == nil {
return &check.CheckerInfo{Name: "MyChecker", Params: []string{"myobtained", "myexpected"}}
}
return checker.info
}
func (checker *MyChecker) Check(params []interface{}, names []string) (bool, string) {
rparams := checker.params
rnames := checker.names
checker.params = append([]interface{}{}, params...)
checker.names = append([]string{}, names...)
if rparams != nil {
copy(params, rparams)
}
if rnames != nil {
copy(names, rnames)
}
return checker.result, checker.error
}
type myCommentType string
func (c myCommentType) CheckCommentString() string {
return string(c)
}
func myComment(s string) myCommentType {
return myCommentType(s)
}
// -----------------------------------------------------------------------
// Ensure a real checker actually works fine.
func (s *HelpersS) TestCheckerInterface(c *check.C) {
testHelperSuccess(c, "Check(1, Equals, 1)", true, func() interface{} {
return c.Check(1, check.Equals, 1)
})
}
// -----------------------------------------------------------------------
// Tests for Check(), mostly the same as for Assert() following these.
func (s *HelpersS) TestCheckSucceedWithExpected(c *check.C) {
checker := &MyChecker{result: true}
testHelperSuccess(c, "Check(1, checker, 2)", true, func() interface{} {
return c.Check(1, checker, 2)
})
if !reflect.DeepEqual(checker.params, []interface{}{1, 2}) {
c.Fatalf("Bad params for check: %#v", checker.params)
}
}
func (s *HelpersS) TestCheckSucceedWithoutExpected(c *check.C) {
checker := &MyChecker{result: true, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
testHelperSuccess(c, "Check(1, checker)", true, func() interface{} {
return c.Check(1, checker)
})
if !reflect.DeepEqual(checker.params, []interface{}{1}) {
c.Fatalf("Bad params for check: %#v", checker.params)
}
}
func (s *HelpersS) TestCheckFailWithExpected(c *check.C) {
checker := &MyChecker{result: false}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, checker, 2\\)\n" +
"\\.+ myobtained int = 1\n" +
"\\.+ myexpected int = 2\n\n"
testHelperFailure(c, "Check(1, checker, 2)", false, false, log,
func() interface{} {
return c.Check(1, checker, 2)
})
}
func (s *HelpersS) TestCheckFailWithExpectedAndComment(c *check.C) {
checker := &MyChecker{result: false}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, checker, 2, myComment\\(\"Hello world!\"\\)\\)\n" +
"\\.+ myobtained int = 1\n" +
"\\.+ myexpected int = 2\n" +
"\\.+ Hello world!\n\n"
testHelperFailure(c, "Check(1, checker, 2, msg)", false, false, log,
func() interface{} {
return c.Check(1, checker, 2, myComment("Hello world!"))
})
}
func (s *HelpersS) TestCheckFailWithExpectedAndStaticComment(c *check.C) {
checker := &MyChecker{result: false}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" // Nice leading comment\\.\n" +
" return c\\.Check\\(1, checker, 2\\) // Hello there\n" +
"\\.+ myobtained int = 1\n" +
"\\.+ myexpected int = 2\n\n"
testHelperFailure(c, "Check(1, checker, 2, msg)", false, false, log,
func() interface{} {
// Nice leading comment.
return c.Check(1, checker, 2) // Hello there
})
}
func (s *HelpersS) TestCheckFailWithoutExpected(c *check.C) {
checker := &MyChecker{result: false, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, checker\\)\n" +
"\\.+ myvalue int = 1\n\n"
testHelperFailure(c, "Check(1, checker)", false, false, log,
func() interface{} {
return c.Check(1, checker)
})
}
func (s *HelpersS) TestCheckFailWithoutExpectedAndMessage(c *check.C) {
checker := &MyChecker{result: false, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, checker, myComment\\(\"Hello world!\"\\)\\)\n" +
"\\.+ myvalue int = 1\n" +
"\\.+ Hello world!\n\n"
testHelperFailure(c, "Check(1, checker, msg)", false, false, log,
func() interface{} {
return c.Check(1, checker, myComment("Hello world!"))
})
}
func (s *HelpersS) TestCheckWithMissingExpected(c *check.C) {
checker := &MyChecker{result: true}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, checker\\)\n" +
"\\.+ Check\\(myobtained, MyChecker, myexpected\\):\n" +
"\\.+ Wrong number of parameters for MyChecker: " +
"want 3, got 2\n\n"
testHelperFailure(c, "Check(1, checker, !?)", false, false, log,
func() interface{} {
return c.Check(1, checker)
})
}
func (s *HelpersS) TestCheckWithTooManyExpected(c *check.C) {
checker := &MyChecker{result: true}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, checker, 2, 3\\)\n" +
"\\.+ Check\\(myobtained, MyChecker, myexpected\\):\n" +
"\\.+ Wrong number of parameters for MyChecker: " +
"want 3, got 4\n\n"
testHelperFailure(c, "Check(1, checker, 2, 3)", false, false, log,
func() interface{} {
return c.Check(1, checker, 2, 3)
})
}
func (s *HelpersS) TestCheckWithError(c *check.C) {
checker := &MyChecker{result: false, error: "Some not so cool data provided!"}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, checker, 2\\)\n" +
"\\.+ myobtained int = 1\n" +
"\\.+ myexpected int = 2\n" +
"\\.+ Some not so cool data provided!\n\n"
testHelperFailure(c, "Check(1, checker, 2)", false, false, log,
func() interface{} {
return c.Check(1, checker, 2)
})
}
func (s *HelpersS) TestCheckWithNilChecker(c *check.C) {
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, nil\\)\n" +
"\\.+ Check\\(obtained, nil!\\?, \\.\\.\\.\\):\n" +
"\\.+ Oops\\.\\. you've provided a nil checker!\n\n"
testHelperFailure(c, "Check(obtained, nil)", false, false, log,
func() interface{} {
return c.Check(1, nil)
})
}
func (s *HelpersS) TestCheckWithParamsAndNamesMutation(c *check.C) {
checker := &MyChecker{result: false, params: []interface{}{3, 4}, names: []string{"newobtained", "newexpected"}}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" return c\\.Check\\(1, checker, 2\\)\n" +
"\\.+ newobtained int = 3\n" +
"\\.+ newexpected int = 4\n\n"
testHelperFailure(c, "Check(1, checker, 2) with mutation", false, false, log,
func() interface{} {
return c.Check(1, checker, 2)
})
}
// -----------------------------------------------------------------------
// Tests for Assert(), mostly the same as for Check() above.
func (s *HelpersS) TestAssertSucceedWithExpected(c *check.C) {
checker := &MyChecker{result: true}
testHelperSuccess(c, "Assert(1, checker, 2)", nil, func() interface{} {
c.Assert(1, checker, 2)
return nil
})
if !reflect.DeepEqual(checker.params, []interface{}{1, 2}) {
c.Fatalf("Bad params for check: %#v", checker.params)
}
}
func (s *HelpersS) TestAssertSucceedWithoutExpected(c *check.C) {
checker := &MyChecker{result: true, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
testHelperSuccess(c, "Assert(1, checker)", nil, func() interface{} {
c.Assert(1, checker)
return nil
})
if !reflect.DeepEqual(checker.params, []interface{}{1}) {
c.Fatalf("Bad params for check: %#v", checker.params)
}
}
func (s *HelpersS) TestAssertFailWithExpected(c *check.C) {
checker := &MyChecker{result: false}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" c\\.Assert\\(1, checker, 2\\)\n" +
"\\.+ myobtained int = 1\n" +
"\\.+ myexpected int = 2\n\n"
testHelperFailure(c, "Assert(1, checker, 2)", nil, true, log,
func() interface{} {
c.Assert(1, checker, 2)
return nil
})
}
func (s *HelpersS) TestAssertFailWithExpectedAndMessage(c *check.C) {
checker := &MyChecker{result: false}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" c\\.Assert\\(1, checker, 2, myComment\\(\"Hello world!\"\\)\\)\n" +
"\\.+ myobtained int = 1\n" +
"\\.+ myexpected int = 2\n" +
"\\.+ Hello world!\n\n"
testHelperFailure(c, "Assert(1, checker, 2, msg)", nil, true, log,
func() interface{} {
c.Assert(1, checker, 2, myComment("Hello world!"))
return nil
})
}
func (s *HelpersS) TestAssertFailWithoutExpected(c *check.C) {
checker := &MyChecker{result: false, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" c\\.Assert\\(1, checker\\)\n" +
"\\.+ myvalue int = 1\n\n"
testHelperFailure(c, "Assert(1, checker)", nil, true, log,
func() interface{} {
c.Assert(1, checker)
return nil
})
}
func (s *HelpersS) TestAssertFailWithoutExpectedAndMessage(c *check.C) {
checker := &MyChecker{result: false, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" c\\.Assert\\(1, checker, myComment\\(\"Hello world!\"\\)\\)\n" +
"\\.+ myvalue int = 1\n" +
"\\.+ Hello world!\n\n"
testHelperFailure(c, "Assert(1, checker, msg)", nil, true, log,
func() interface{} {
c.Assert(1, checker, myComment("Hello world!"))
return nil
})
}
func (s *HelpersS) TestAssertWithMissingExpected(c *check.C) {
checker := &MyChecker{result: true}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" c\\.Assert\\(1, checker\\)\n" +
"\\.+ Assert\\(myobtained, MyChecker, myexpected\\):\n" +
"\\.+ Wrong number of parameters for MyChecker: " +
"want 3, got 2\n\n"
testHelperFailure(c, "Assert(1, checker, !?)", nil, true, log,
func() interface{} {
c.Assert(1, checker)
return nil
})
}
func (s *HelpersS) TestAssertWithError(c *check.C) {
checker := &MyChecker{result: false, error: "Some not so cool data provided!"}
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" c\\.Assert\\(1, checker, 2\\)\n" +
"\\.+ myobtained int = 1\n" +
"\\.+ myexpected int = 2\n" +
"\\.+ Some not so cool data provided!\n\n"
testHelperFailure(c, "Assert(1, checker, 2)", nil, true, log,
func() interface{} {
c.Assert(1, checker, 2)
return nil
})
}
func (s *HelpersS) TestAssertWithNilChecker(c *check.C) {
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
" c\\.Assert\\(1, nil\\)\n" +
"\\.+ Assert\\(obtained, nil!\\?, \\.\\.\\.\\):\n" +
"\\.+ Oops\\.\\. you've provided a nil checker!\n\n"
testHelperFailure(c, "Assert(obtained, nil)", nil, true, log,
func() interface{} {
c.Assert(1, nil)
return nil
})
}
// -----------------------------------------------------------------------
// Ensure that values logged work properly in some interesting cases.
func (s *HelpersS) TestValueLoggingWithArrays(c *check.C) {
checker := &MyChecker{result: false}
log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
" return c\\.Check\\(\\[\\]byte{1, 2}, checker, \\[\\]byte{1, 3}\\)\n" +
"\\.+ myobtained \\[\\]uint8 = \\[\\]byte{0x1, 0x2}\n" +
"\\.+ myexpected \\[\\]uint8 = \\[\\]byte{0x1, 0x3}\n\n"
testHelperFailure(c, "Check([]byte{1}, chk, []byte{3})", false, false, log,
func() interface{} {
return c.Check([]byte{1, 2}, checker, []byte{1, 3})
})
}
func (s *HelpersS) TestValueLoggingWithMultiLine(c *check.C) {
checker := &MyChecker{result: false}
log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
" return c\\.Check\\(\"a\\\\nb\\\\n\", checker, \"a\\\\nb\\\\nc\"\\)\n" +
"\\.+ myobtained string = \"\" \\+\n" +
"\\.+ \"a\\\\n\" \\+\n" +
"\\.+ \"b\\\\n\"\n" +
"\\.+ myexpected string = \"\" \\+\n" +
"\\.+ \"a\\\\n\" \\+\n" +
"\\.+ \"b\\\\n\" \\+\n" +
"\\.+ \"c\"\n\n"
testHelperFailure(c, `Check("a\nb\n", chk, "a\nb\nc")`, false, false, log,
func() interface{} {
return c.Check("a\nb\n", checker, "a\nb\nc")
})
}
func (s *HelpersS) TestValueLoggingWithMultiLineException(c *check.C) {
// If the newline is at the end of the string, don't log as multi-line.
checker := &MyChecker{result: false}
log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
" return c\\.Check\\(\"a b\\\\n\", checker, \"a\\\\nb\"\\)\n" +
"\\.+ myobtained string = \"a b\\\\n\"\n" +
"\\.+ myexpected string = \"\" \\+\n" +
"\\.+ \"a\\\\n\" \\+\n" +
"\\.+ \"b\"\n\n"
testHelperFailure(c, `Check("a b\n", chk, "a\nb")`, false, false, log,
func() interface{} {
return c.Check("a b\n", checker, "a\nb")
})
}
// -----------------------------------------------------------------------
// MakeDir() tests.
type MkDirHelper struct {
path1 string
path2 string
isDir1 bool
isDir2 bool
isDir3 bool
isDir4 bool
}
func (s *MkDirHelper) SetUpSuite(c *check.C) {
s.path1 = c.MkDir()
s.isDir1 = isDir(s.path1)
}
func (s *MkDirHelper) Test(c *check.C) {
s.path2 = c.MkDir()
s.isDir2 = isDir(s.path2)
}
func (s *MkDirHelper) TearDownSuite(c *check.C) {
s.isDir3 = isDir(s.path1)
s.isDir4 = isDir(s.path2)
}
func (s *HelpersS) TestMkDir(c *check.C) {
helper := MkDirHelper{}
output := String{}
check.Run(&helper, &check.RunConf{Output: &output})
c.Assert(output.value, check.Equals, "")
c.Check(helper.isDir1, check.Equals, true)
c.Check(helper.isDir2, check.Equals, true)
c.Check(helper.isDir3, check.Equals, true)
c.Check(helper.isDir4, check.Equals, true)
c.Check(helper.path1, check.Not(check.Equals),
helper.path2)
c.Check(isDir(helper.path1), check.Equals, false)
c.Check(isDir(helper.path2), check.Equals, false)
}
func isDir(path string) bool {
if stat, err := os.Stat(path); err == nil {
return stat.IsDir()
}
return false
}
// Concurrent logging should not corrupt the underling buffer.
// Use go test -race to detect the race in this test.
func (s *HelpersS) TestConcurrentLogging(c *check.C) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))
var start, stop sync.WaitGroup
start.Add(1)
for i, n := 0, runtime.NumCPU()*2; i < n; i++ {
stop.Add(1)
go func(i int) {
start.Wait()
for j := 0; j < 30; j++ {
c.Logf("Worker %d: line %d", i, j)
}
stop.Done()
}(i)
}
start.Done()
stop.Wait()
}
// -----------------------------------------------------------------------
// Test the TestName function
type TestNameHelper struct {
name1 string
name2 string
name3 string
name4 string
name5 string
}
func (s *TestNameHelper) SetUpSuite(c *check.C) { s.name1 = c.TestName() }
func (s *TestNameHelper) SetUpTest(c *check.C) { s.name2 = c.TestName() }
func (s *TestNameHelper) Test(c *check.C) { s.name3 = c.TestName() }
func (s *TestNameHelper) TearDownTest(c *check.C) { s.name4 = c.TestName() }
func (s *TestNameHelper) TearDownSuite(c *check.C) { s.name5 = c.TestName() }
func (s *HelpersS) TestTestName(c *check.C) {
helper := TestNameHelper{}
output := String{}
check.Run(&helper, &check.RunConf{Output: &output})
c.Check(helper.name1, check.Equals, "")
c.Check(helper.name2, check.Equals, "TestNameHelper.Test")
c.Check(helper.name3, check.Equals, "TestNameHelper.Test")
c.Check(helper.name4, check.Equals, "TestNameHelper.Test")
c.Check(helper.name5, check.Equals, "")
}
// -----------------------------------------------------------------------
// A couple of helper functions to test helper functions. :-)
func testHelperSuccess(c *check.C, name string, expectedResult interface{}, closure func() interface{}) {
var result interface{}
defer (func() {
if err := recover(); err != nil {
panic(err)
}
checkState(c, result,
&expectedState{
name: name,
result: expectedResult,
failed: false,
log: "",
})
})()
result = closure()
}
func testHelperFailure(c *check.C, name string, expectedResult interface{}, shouldStop bool, log string, closure func() interface{}) {
var result interface{}
defer (func() {
if err := recover(); err != nil {
panic(err)
}
checkState(c, result,
&expectedState{
name: name,
result: expectedResult,
failed: true,
log: log,
})
})()
result = closure()
if shouldStop {
c.Logf("%s didn't stop when it should", name)
}
}
+168
View File
@@ -0,0 +1,168 @@
package check
import (
"bytes"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"os"
)
func indent(s, with string) (r string) {
eol := true
for i := 0; i != len(s); i++ {
c := s[i]
switch {
case eol && c == '\n' || c == '\r':
case c == '\n' || c == '\r':
eol = true
case eol:
eol = false
s = s[:i] + with + s[i:]
i += len(with)
}
}
return s
}
func printLine(filename string, line int) (string, error) {
fset := token.NewFileSet()
file, err := os.Open(filename)
if err != nil {
return "", err
}
fnode, err := parser.ParseFile(fset, filename, file, parser.ParseComments)
if err != nil {
return "", err
}
config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}
lp := &linePrinter{fset: fset, fnode: fnode, line: line, config: config}
ast.Walk(lp, fnode)
result := lp.output.Bytes()
// Comments leave \n at the end.
n := len(result)
for n > 0 && result[n-1] == '\n' {
n--
}
return string(result[:n]), nil
}
type linePrinter struct {
config *printer.Config
fset *token.FileSet
fnode *ast.File
line int
output bytes.Buffer
stmt ast.Stmt
}
func (lp *linePrinter) emit() bool {
if lp.stmt != nil {
lp.trim(lp.stmt)
lp.printWithComments(lp.stmt)
lp.stmt = nil
return true
}
return false
}
func (lp *linePrinter) printWithComments(n ast.Node) {
nfirst := lp.fset.Position(n.Pos()).Line
nlast := lp.fset.Position(n.End()).Line
for _, g := range lp.fnode.Comments {
cfirst := lp.fset.Position(g.Pos()).Line
clast := lp.fset.Position(g.End()).Line
if clast == nfirst-1 && lp.fset.Position(n.Pos()).Column == lp.fset.Position(g.Pos()).Column {
for _, c := range g.List {
lp.output.WriteString(c.Text)
lp.output.WriteByte('\n')
}
}
if cfirst >= nfirst && cfirst <= nlast && n.End() <= g.List[0].Slash {
// The printer will not include the comment if it starts past
// the node itself. Trick it into printing by overlapping the
// slash with the end of the statement.
g.List[0].Slash = n.End() - 1
}
}
node := &printer.CommentedNode{n, lp.fnode.Comments}
lp.config.Fprint(&lp.output, lp.fset, node)
}
func (lp *linePrinter) Visit(n ast.Node) (w ast.Visitor) {
if n == nil {
if lp.output.Len() == 0 {
lp.emit()
}
return nil
}
first := lp.fset.Position(n.Pos()).Line
last := lp.fset.Position(n.End()).Line
if first <= lp.line && last >= lp.line {
// Print the innermost statement containing the line.
if stmt, ok := n.(ast.Stmt); ok {
if _, ok := n.(*ast.BlockStmt); !ok {
lp.stmt = stmt
}
}
if first == lp.line && lp.emit() {
return nil
}
return lp
}
return nil
}
func (lp *linePrinter) trim(n ast.Node) bool {
stmt, ok := n.(ast.Stmt)
if !ok {
return true
}
line := lp.fset.Position(n.Pos()).Line
if line != lp.line {
return false
}
switch stmt := stmt.(type) {
case *ast.IfStmt:
stmt.Body = lp.trimBlock(stmt.Body)
case *ast.SwitchStmt:
stmt.Body = lp.trimBlock(stmt.Body)
case *ast.TypeSwitchStmt:
stmt.Body = lp.trimBlock(stmt.Body)
case *ast.CaseClause:
stmt.Body = lp.trimList(stmt.Body)
case *ast.CommClause:
stmt.Body = lp.trimList(stmt.Body)
case *ast.BlockStmt:
stmt.List = lp.trimList(stmt.List)
}
return true
}
func (lp *linePrinter) trimBlock(stmt *ast.BlockStmt) *ast.BlockStmt {
if !lp.trim(stmt) {
return lp.emptyBlock(stmt)
}
stmt.Rbrace = stmt.Lbrace
return stmt
}
func (lp *linePrinter) trimList(stmts []ast.Stmt) []ast.Stmt {
for i := 0; i != len(stmts); i++ {
if !lp.trim(stmts[i]) {
stmts[i] = lp.emptyStmt(stmts[i])
break
}
}
return stmts
}
func (lp *linePrinter) emptyStmt(n ast.Node) *ast.ExprStmt {
return &ast.ExprStmt{&ast.Ellipsis{n.Pos(), nil}}
}
func (lp *linePrinter) emptyBlock(n ast.Node) *ast.BlockStmt {
p := n.Pos()
return &ast.BlockStmt{p, []ast.Stmt{lp.emptyStmt(n)}, p}
}
+110
View File
@@ -0,0 +1,110 @@
package check_test
import (
. "github.com/minio/check"
)
var _ = Suite(&PrinterS{})
type PrinterS struct{}
func (s *PrinterS) TestCountSuite(c *C) {
suitesRun += 1
}
var printTestFuncLine int
func init() {
printTestFuncLine = getMyLine() + 3
}
func printTestFunc() {
println(1) // Comment1
if 2 == 2 { // Comment2
println(3) // Comment3
}
switch 5 {
case 6:
println(6) // Comment6
println(7)
}
switch interface{}(9).(type) { // Comment9
case int:
println(10)
println(11)
}
select {
case <-(chan bool)(nil):
println(14)
println(15)
default:
println(16)
println(17)
}
println(19,
20)
_ = func() {
println(21)
println(22)
}
println(24, func() {
println(25)
})
// Leading comment
// with multiple lines.
println(29) // Comment29
}
var printLineTests = []struct {
line int
output string
}{
{1, "println(1) // Comment1"},
{2, "if 2 == 2 { // Comment2\n ...\n}"},
{3, "println(3) // Comment3"},
{5, "switch 5 {\n...\n}"},
{6, "case 6:\n println(6) // Comment6\n ..."},
{7, "println(7)"},
{9, "switch interface{}(9).(type) { // Comment9\n...\n}"},
{10, "case int:\n println(10)\n ..."},
{14, "case <-(chan bool)(nil):\n println(14)\n ..."},
{15, "println(15)"},
{16, "default:\n println(16)\n ..."},
{17, "println(17)"},
{19, "println(19,\n 20)"},
{20, "println(19,\n 20)"},
{21, "_ = func() {\n println(21)\n println(22)\n}"},
{22, "println(22)"},
{24, "println(24, func() {\n println(25)\n})"},
{25, "println(25)"},
{26, "println(24, func() {\n println(25)\n})"},
{29, "// Leading comment\n// with multiple lines.\nprintln(29) // Comment29"},
}
// reformat broke test lines above
//func (s *PrinterS) TestPrintLine(c *C) {
// for _, test := range printLineTests {
// output, err := PrintLine("printer_test.go", printTestFuncLine+test.line)
// c.Assert(err, IsNil)
// c.Assert(output, Equals, test.output)
// }
//}
var indentTests = []struct {
in, out string
}{
{"", ""},
{"\n", "\n"},
{"a", ">>>a"},
{"a\n", ">>>a\n"},
{"a\nb", ">>>a\n>>>b"},
{" ", ">>> "},
}
func (s *PrinterS) TestIndent(c *C) {
for _, test := range indentTests {
out := Indent(test.in, ">>>")
c.Assert(out, Equals, test.out)
}
}
+175
View File
@@ -0,0 +1,175 @@
package check
import (
"bufio"
"flag"
"fmt"
"os"
"testing"
"time"
)
// -----------------------------------------------------------------------
// Test suite registry.
var allSuites []interface{}
// Suite registers the given value as a test suite to be run. Any methods
// starting with the Test prefix in the given value will be considered as
// a test method.
func Suite(suite interface{}) interface{} {
allSuites = append(allSuites, suite)
return suite
}
// -----------------------------------------------------------------------
// Public running interface.
var (
oldFilterFlag = flag.String("gocheck.f", "", "Regular expression selecting which tests and/or suites to run")
oldVerboseFlag = flag.Bool("gocheck.v", false, "Verbose mode")
oldStreamFlag = flag.Bool("gocheck.vv", false, "Super verbose mode (disables output caching)")
oldBenchFlag = flag.Bool("gocheck.b", false, "Run benchmarks")
oldBenchTime = flag.Duration("gocheck.btime", 1*time.Second, "approximate run time for each benchmark")
oldListFlag = flag.Bool("gocheck.list", false, "List the names of all tests that will be run")
oldWorkFlag = flag.Bool("gocheck.work", false, "Display and do not remove the test working directory")
newFilterFlag = flag.String("check.f", "", "Regular expression selecting which tests and/or suites to run")
newVerboseFlag = flag.Bool("check.v", false, "Verbose mode")
newStreamFlag = flag.Bool("check.vv", false, "Super verbose mode (disables output caching)")
newBenchFlag = flag.Bool("check.b", false, "Run benchmarks")
newBenchTime = flag.Duration("check.btime", 1*time.Second, "approximate run time for each benchmark")
newBenchMem = flag.Bool("check.bmem", false, "Report memory benchmarks")
newListFlag = flag.Bool("check.list", false, "List the names of all tests that will be run")
newWorkFlag = flag.Bool("check.work", false, "Display and do not remove the test working directory")
)
// TestingT runs all test suites registered with the Suite function,
// printing results to stdout, and reporting any failures back to
// the "testing" package.
func TestingT(testingT *testing.T) {
benchTime := *newBenchTime
if benchTime == 1*time.Second {
benchTime = *oldBenchTime
}
conf := &RunConf{
Filter: *oldFilterFlag + *newFilterFlag,
Verbose: *oldVerboseFlag || *newVerboseFlag,
Stream: *oldStreamFlag || *newStreamFlag,
Benchmark: *oldBenchFlag || *newBenchFlag,
BenchmarkTime: benchTime,
BenchmarkMem: *newBenchMem,
KeepWorkDir: *oldWorkFlag || *newWorkFlag,
}
if *oldListFlag || *newListFlag {
w := bufio.NewWriter(os.Stdout)
for _, name := range ListAll(conf) {
fmt.Fprintln(w, name)
}
w.Flush()
return
}
result := RunAll(conf)
println(result.String())
if !result.Passed() {
testingT.Fail()
}
}
// RunAll runs all test suites registered with the Suite function, using the
// provided run configuration.
func RunAll(runConf *RunConf) *Result {
result := Result{}
for _, suite := range allSuites {
result.Add(Run(suite, runConf))
}
return &result
}
// Run runs the provided test suite using the provided run configuration.
func Run(suite interface{}, runConf *RunConf) *Result {
runner := newSuiteRunner(suite, runConf)
return runner.run()
}
// ListAll returns the names of all the test functions registered with the
// Suite function that will be run with the provided run configuration.
func ListAll(runConf *RunConf) []string {
var names []string
for _, suite := range allSuites {
names = append(names, List(suite, runConf)...)
}
return names
}
// List returns the names of the test functions in the given
// suite that will be run with the provided run configuration.
func List(suite interface{}, runConf *RunConf) []string {
var names []string
runner := newSuiteRunner(suite, runConf)
for _, t := range runner.tests {
names = append(names, t.String())
}
return names
}
// -----------------------------------------------------------------------
// Result methods.
func (r *Result) Add(other *Result) {
r.Succeeded += other.Succeeded
r.Skipped += other.Skipped
r.Failed += other.Failed
r.Panicked += other.Panicked
r.FixturePanicked += other.FixturePanicked
r.ExpectedFailures += other.ExpectedFailures
r.Missed += other.Missed
if r.WorkDir != "" && other.WorkDir != "" {
r.WorkDir += ":" + other.WorkDir
} else if other.WorkDir != "" {
r.WorkDir = other.WorkDir
}
}
func (r *Result) Passed() bool {
return (r.Failed == 0 && r.Panicked == 0 &&
r.FixturePanicked == 0 && r.Missed == 0 &&
r.RunError == nil)
}
func (r *Result) String() string {
if r.RunError != nil {
return "ERROR: " + r.RunError.Error()
}
var value string
if r.Failed == 0 && r.Panicked == 0 && r.FixturePanicked == 0 &&
r.Missed == 0 {
value = "OK: "
} else {
value = "OOPS: "
}
value += fmt.Sprintf("%d passed", r.Succeeded)
if r.Skipped != 0 {
value += fmt.Sprintf(", %d skipped", r.Skipped)
}
if r.ExpectedFailures != 0 {
value += fmt.Sprintf(", %d expected failures", r.ExpectedFailures)
}
if r.Failed != 0 {
value += fmt.Sprintf(", %d FAILED", r.Failed)
}
if r.Panicked != 0 {
value += fmt.Sprintf(", %d PANICKED", r.Panicked)
}
if r.FixturePanicked != 0 {
value += fmt.Sprintf(", %d FIXTURE-PANICKED", r.FixturePanicked)
}
if r.Missed != 0 {
value += fmt.Sprintf(", %d MISSED", r.Missed)
}
if r.WorkDir != "" {
value += "\nWORK=" + r.WorkDir
}
return value
}
+419
View File
@@ -0,0 +1,419 @@
// These tests verify the test running logic.
package check_test
import (
"errors"
. "github.com/minio/check"
"os"
"sync"
)
var runnerS = Suite(&RunS{})
type RunS struct{}
func (s *RunS) TestCountSuite(c *C) {
suitesRun += 1
}
// -----------------------------------------------------------------------
// Tests ensuring result counting works properly.
func (s *RunS) TestSuccess(c *C) {
output := String{}
result := Run(&SuccessHelper{}, &RunConf{Output: &output})
c.Check(result.Succeeded, Equals, 1)
c.Check(result.Failed, Equals, 0)
c.Check(result.Skipped, Equals, 0)
c.Check(result.Panicked, Equals, 0)
c.Check(result.FixturePanicked, Equals, 0)
c.Check(result.Missed, Equals, 0)
c.Check(result.RunError, IsNil)
}
func (s *RunS) TestFailure(c *C) {
output := String{}
result := Run(&FailHelper{}, &RunConf{Output: &output})
c.Check(result.Succeeded, Equals, 0)
c.Check(result.Failed, Equals, 1)
c.Check(result.Skipped, Equals, 0)
c.Check(result.Panicked, Equals, 0)
c.Check(result.FixturePanicked, Equals, 0)
c.Check(result.Missed, Equals, 0)
c.Check(result.RunError, IsNil)
}
func (s *RunS) TestFixture(c *C) {
output := String{}
result := Run(&FixtureHelper{}, &RunConf{Output: &output})
c.Check(result.Succeeded, Equals, 2)
c.Check(result.Failed, Equals, 0)
c.Check(result.Skipped, Equals, 0)
c.Check(result.Panicked, Equals, 0)
c.Check(result.FixturePanicked, Equals, 0)
c.Check(result.Missed, Equals, 0)
c.Check(result.RunError, IsNil)
}
func (s *RunS) TestPanicOnTest(c *C) {
output := String{}
helper := &FixtureHelper{panicOn: "Test1"}
result := Run(helper, &RunConf{Output: &output})
c.Check(result.Succeeded, Equals, 1)
c.Check(result.Failed, Equals, 0)
c.Check(result.Skipped, Equals, 0)
c.Check(result.Panicked, Equals, 1)
c.Check(result.FixturePanicked, Equals, 0)
c.Check(result.Missed, Equals, 0)
c.Check(result.RunError, IsNil)
}
func (s *RunS) TestPanicOnSetUpTest(c *C) {
output := String{}
helper := &FixtureHelper{panicOn: "SetUpTest"}
result := Run(helper, &RunConf{Output: &output})
c.Check(result.Succeeded, Equals, 0)
c.Check(result.Failed, Equals, 0)
c.Check(result.Skipped, Equals, 0)
c.Check(result.Panicked, Equals, 0)
c.Check(result.FixturePanicked, Equals, 1)
c.Check(result.Missed, Equals, 2)
c.Check(result.RunError, IsNil)
}
func (s *RunS) TestPanicOnSetUpSuite(c *C) {
output := String{}
helper := &FixtureHelper{panicOn: "SetUpSuite"}
result := Run(helper, &RunConf{Output: &output})
c.Check(result.Succeeded, Equals, 0)
c.Check(result.Failed, Equals, 0)
c.Check(result.Skipped, Equals, 0)
c.Check(result.Panicked, Equals, 0)
c.Check(result.FixturePanicked, Equals, 1)
c.Check(result.Missed, Equals, 2)
c.Check(result.RunError, IsNil)
}
// -----------------------------------------------------------------------
// Check result aggregation.
func (s *RunS) TestAdd(c *C) {
result := &Result{
Succeeded: 1,
Skipped: 2,
Failed: 3,
Panicked: 4,
FixturePanicked: 5,
Missed: 6,
ExpectedFailures: 7,
}
result.Add(&Result{
Succeeded: 10,
Skipped: 20,
Failed: 30,
Panicked: 40,
FixturePanicked: 50,
Missed: 60,
ExpectedFailures: 70,
})
c.Check(result.Succeeded, Equals, 11)
c.Check(result.Skipped, Equals, 22)
c.Check(result.Failed, Equals, 33)
c.Check(result.Panicked, Equals, 44)
c.Check(result.FixturePanicked, Equals, 55)
c.Check(result.Missed, Equals, 66)
c.Check(result.ExpectedFailures, Equals, 77)
c.Check(result.RunError, IsNil)
}
// -----------------------------------------------------------------------
// Check the Passed() method.
func (s *RunS) TestPassed(c *C) {
c.Assert((&Result{}).Passed(), Equals, true)
c.Assert((&Result{Succeeded: 1}).Passed(), Equals, true)
c.Assert((&Result{Skipped: 1}).Passed(), Equals, true)
c.Assert((&Result{Failed: 1}).Passed(), Equals, false)
c.Assert((&Result{Panicked: 1}).Passed(), Equals, false)
c.Assert((&Result{FixturePanicked: 1}).Passed(), Equals, false)
c.Assert((&Result{Missed: 1}).Passed(), Equals, false)
c.Assert((&Result{RunError: errors.New("!")}).Passed(), Equals, false)
}
// -----------------------------------------------------------------------
// Check that result printing is working correctly.
func (s *RunS) TestPrintSuccess(c *C) {
result := &Result{Succeeded: 5}
c.Check(result.String(), Equals, "OK: 5 passed")
}
func (s *RunS) TestPrintFailure(c *C) {
result := &Result{Failed: 5}
c.Check(result.String(), Equals, "OOPS: 0 passed, 5 FAILED")
}
func (s *RunS) TestPrintSkipped(c *C) {
result := &Result{Skipped: 5}
c.Check(result.String(), Equals, "OK: 0 passed, 5 skipped")
}
func (s *RunS) TestPrintExpectedFailures(c *C) {
result := &Result{ExpectedFailures: 5}
c.Check(result.String(), Equals, "OK: 0 passed, 5 expected failures")
}
func (s *RunS) TestPrintPanicked(c *C) {
result := &Result{Panicked: 5}
c.Check(result.String(), Equals, "OOPS: 0 passed, 5 PANICKED")
}
func (s *RunS) TestPrintFixturePanicked(c *C) {
result := &Result{FixturePanicked: 5}
c.Check(result.String(), Equals, "OOPS: 0 passed, 5 FIXTURE-PANICKED")
}
func (s *RunS) TestPrintMissed(c *C) {
result := &Result{Missed: 5}
c.Check(result.String(), Equals, "OOPS: 0 passed, 5 MISSED")
}
func (s *RunS) TestPrintAll(c *C) {
result := &Result{Succeeded: 1, Skipped: 2, ExpectedFailures: 3,
Panicked: 4, FixturePanicked: 5, Missed: 6}
c.Check(result.String(), Equals,
"OOPS: 1 passed, 2 skipped, 3 expected failures, 4 PANICKED, "+
"5 FIXTURE-PANICKED, 6 MISSED")
}
func (s *RunS) TestPrintRunError(c *C) {
result := &Result{Succeeded: 1, Failed: 1,
RunError: errors.New("Kaboom!")}
c.Check(result.String(), Equals, "ERROR: Kaboom!")
}
// -----------------------------------------------------------------------
// Verify that the method pattern flag works correctly.
func (s *RunS) TestFilterTestName(c *C) {
helper := FixtureHelper{}
output := String{}
runConf := RunConf{Output: &output, Filter: "Test[91]"}
Run(&helper, &runConf)
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 5)
}
func (s *RunS) TestFilterTestNameWithAll(c *C) {
helper := FixtureHelper{}
output := String{}
runConf := RunConf{Output: &output, Filter: ".*"}
Run(&helper, &runConf)
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "SetUpTest")
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 8)
}
func (s *RunS) TestFilterSuiteName(c *C) {
helper := FixtureHelper{}
output := String{}
runConf := RunConf{Output: &output, Filter: "FixtureHelper"}
Run(&helper, &runConf)
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "SetUpTest")
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 8)
}
func (s *RunS) TestFilterSuiteNameAndTestName(c *C) {
helper := FixtureHelper{}
output := String{}
runConf := RunConf{Output: &output, Filter: "FixtureHelper\\.Test2"}
Run(&helper, &runConf)
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "Test2")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "TearDownSuite")
c.Check(len(helper.calls), Equals, 5)
}
func (s *RunS) TestFilterAllOut(c *C) {
helper := FixtureHelper{}
output := String{}
runConf := RunConf{Output: &output, Filter: "NotFound"}
Run(&helper, &runConf)
c.Check(len(helper.calls), Equals, 0)
}
func (s *RunS) TestRequirePartialMatch(c *C) {
helper := FixtureHelper{}
output := String{}
runConf := RunConf{Output: &output, Filter: "est"}
Run(&helper, &runConf)
c.Check(len(helper.calls), Equals, 8)
}
func (s *RunS) TestFilterError(c *C) {
helper := FixtureHelper{}
output := String{}
runConf := RunConf{Output: &output, Filter: "]["}
result := Run(&helper, &runConf)
c.Check(result.String(), Equals,
"ERROR: Bad filter expression: error parsing regexp: missing closing ]: `[`")
c.Check(len(helper.calls), Equals, 0)
}
// -----------------------------------------------------------------------
// Verify that List works correctly.
func (s *RunS) TestListFiltered(c *C) {
names := List(&FixtureHelper{}, &RunConf{Filter: "1"})
c.Assert(names, DeepEquals, []string{
"FixtureHelper.Test1",
})
}
func (s *RunS) TestList(c *C) {
names := List(&FixtureHelper{}, &RunConf{})
c.Assert(names, DeepEquals, []string{
"FixtureHelper.Test1",
"FixtureHelper.Test2",
})
}
// -----------------------------------------------------------------------
// Verify that verbose mode prints tests which pass as well.
func (s *RunS) TestVerboseMode(c *C) {
helper := FixtureHelper{}
output := String{}
runConf := RunConf{Output: &output, Verbose: true}
Run(&helper, &runConf)
expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test1\t *[.0-9]+s\n" +
"PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test2\t *[.0-9]+s\n"
c.Assert(output.value, Matches, expected)
}
func (s *RunS) TestVerboseModeWithFailBeforePass(c *C) {
helper := FixtureHelper{panicOn: "Test1"}
output := String{}
runConf := RunConf{Output: &output, Verbose: true}
Run(&helper, &runConf)
expected := "(?s).*PANIC.*\n-+\n" + // Should have an extra line.
"PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test2\t *[.0-9]+s\n"
c.Assert(output.value, Matches, expected)
}
// -----------------------------------------------------------------------
// Verify the stream output mode. In this mode there's no output caching.
type StreamHelper struct {
l2 sync.Mutex
l3 sync.Mutex
}
func (s *StreamHelper) SetUpSuite(c *C) {
c.Log("0")
}
func (s *StreamHelper) Test1(c *C) {
c.Log("1")
s.l2.Lock()
s.l3.Lock()
go func() {
s.l2.Lock() // Wait for "2".
c.Log("3")
s.l3.Unlock()
}()
}
func (s *StreamHelper) Test2(c *C) {
c.Log("2")
s.l2.Unlock()
s.l3.Lock() // Wait for "3".
c.Fail()
c.Log("4")
}
func (s *RunS) TestStreamMode(c *C) {
helper := &StreamHelper{}
output := String{}
runConf := RunConf{Output: &output, Stream: true}
Run(helper, &runConf)
expected := "START: run_test\\.go:[0-9]+: StreamHelper\\.SetUpSuite\n0\n" +
"PASS: run_test\\.go:[0-9]+: StreamHelper\\.SetUpSuite\t *[.0-9]+s\n\n" +
"START: run_test\\.go:[0-9]+: StreamHelper\\.Test1\n1\n" +
"PASS: run_test\\.go:[0-9]+: StreamHelper\\.Test1\t *[.0-9]+s\n\n" +
"START: run_test\\.go:[0-9]+: StreamHelper\\.Test2\n2\n3\n4\n" +
"FAIL: run_test\\.go:[0-9]+: StreamHelper\\.Test2\n\n"
c.Assert(output.value, Matches, expected)
}
type StreamMissHelper struct{}
func (s *StreamMissHelper) SetUpSuite(c *C) {
c.Log("0")
c.Fail()
}
func (s *StreamMissHelper) Test1(c *C) {
c.Log("1")
}
func (s *RunS) TestStreamModeWithMiss(c *C) {
helper := &StreamMissHelper{}
output := String{}
runConf := RunConf{Output: &output, Stream: true}
Run(helper, &runConf)
expected := "START: run_test\\.go:[0-9]+: StreamMissHelper\\.SetUpSuite\n0\n" +
"FAIL: run_test\\.go:[0-9]+: StreamMissHelper\\.SetUpSuite\n\n" +
"START: run_test\\.go:[0-9]+: StreamMissHelper\\.Test1\n" +
"MISS: run_test\\.go:[0-9]+: StreamMissHelper\\.Test1\n\n"
c.Assert(output.value, Matches, expected)
}
// -----------------------------------------------------------------------
// Verify that that the keep work dir request indeed does so.
type WorkDirSuite struct{}
func (s *WorkDirSuite) Test(c *C) {
c.MkDir()
}
func (s *RunS) TestKeepWorkDir(c *C) {
output := String{}
runConf := RunConf{Output: &output, Verbose: true, KeepWorkDir: true}
result := Run(&WorkDirSuite{}, &runConf)
c.Assert(result.String(), Matches, ".*\nWORK="+result.WorkDir)
stat, err := os.Stat(result.WorkDir)
c.Assert(err, IsNil)
c.Assert(stat.IsDir(), Equals, true)
}
+6
View File
@@ -0,0 +1,6 @@
language: go
go: 1.1
script:
- go vet ./...
- go test -v ./...
+21
View File
@@ -0,0 +1,21 @@
Copyright (C) 2013 Jeremy Saenz
All Rights Reserved.
MIT LICENSE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+296
View File
@@ -0,0 +1,296 @@
# cli.go
cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way. - This is a fork of ``github.com/codegangsta/cli`` until our patches get merge upstream
You can view the API docs here:
http://godoc.org/github.com/minio/cli
## Overview
Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags should not hinder productivity when writing a command line app.
**This is where cli.go comes into play.** cli.go makes command line programming fun, organized, and expressive!
## Installation
Make sure you have a working Go environment (go 1.1 is *required*). [See the install instructions](http://golang.org/doc/install.html).
To install `cli.go`, simply run:
```
$ go get github.com/minio/cli
```
Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used:
```
export PATH=$PATH:$GOPATH/bin
```
## Getting Started
One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`.
``` go
package main
import (
"os"
"github.com/minio/cli"
)
func main() {
cli.NewApp().Run(os.Args)
}
```
This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation:
``` go
package main
import (
"os"
"github.com/minio/cli"
)
func main() {
app := cli.NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Action = func(c *cli.Context) {
println("boom! I say!")
}
app.Run(os.Args)
}
```
Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below.
## Example
Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness!
Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it:
``` go
package main
import (
"os"
"github.com/minio/cli"
)
func main() {
app := cli.NewApp()
app.Name = "greet"
app.Usage = "fight the loneliness!"
app.Action = func(c *cli.Context) {
println("Hello friend!")
}
app.Run(os.Args)
}
```
Install our command to the `$GOPATH/bin` directory:
```
$ go install
```
Finally run our new command:
```
$ greet
Hello friend!
```
cli.go also generates some bitchass help text:
```
$ greet help
NAME:
greet - fight the loneliness!
USAGE:
greet [global flags] command [command flags] [arguments...]
VERSION:
0.0.0
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL FLAGS
--version Shows version information
```
### Arguments
You can lookup arguments by calling the `Args` function on `cli.Context`.
``` go
...
app.Action = func(c *cli.Context) {
println("Hello", c.Args()[0])
}
...
```
### Flags
Setting and querying flags is simple.
``` go
...
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
}
app.Action = func(c *cli.Context) {
name := "someone"
if len(c.Args()) > 0 {
name = c.Args()[0]
}
if c.String("lang") == "spanish" {
println("Hola", name)
} else {
println("Hello", name)
}
}
...
```
#### Alternate Names
You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
},
}
```
That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error.
#### Values from the Environment
You can also have the default value set from the environment via `EnvVar`. e.g.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
EnvVar: "APP_LANG",
},
}
```
The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
},
}
```
### Subcommands
Subcommands can be defined for a more git-like command line app.
```go
...
app.Commands = []cli.Command{
{
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *cli.Context) {
println("added task: ", c.Args().First())
},
},
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
},
{
Name: "template",
Aliases: []string{"r"},
Usage: "flags for task templates",
Subcommands: []cli.Command{
{
Name: "add",
Usage: "add a new template",
Action: func(c *cli.Context) {
println("new task template: ", c.Args().First())
},
},
{
Name: "remove",
Usage: "remove an existing template",
Action: func(c *cli.Context) {
println("removed task template: ", c.Args().First())
},
},
},
},
}
...
```
### Bash Completion
You can enable completion commands by setting the `EnableBashCompletion`
flag on the `App` object. By default, this setting will only auto-complete to
show an app's subcommands, but you can write your own completion methods for
the App or its subcommands.
```go
...
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
app := cli.NewApp()
app.EnableBashCompletion = true
app.Commands = []cli.Command{
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
BashComplete: func(c *cli.Context) {
// This will complete if no args are passed
if len(c.Args()) > 0 {
return
}
for _, t := range tasks {
fmt.Println(t)
}
},
}
}
...
```
#### To Enable
Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
setting the `PROG` variable to the name of your program:
`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
## Contribution Guidelines
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.
+332
View File
@@ -0,0 +1,332 @@
package cli
import (
"fmt"
"io"
"os"
"os/exec"
"strings"
"io/ioutil"
"text/tabwriter"
"text/template"
)
// App is the main structure of a cli application. It is recomended that
// and app be created with the cli.NewApp() function
type App struct {
// The name of the program. Defaults to os.Args[0]
Name string
// Description of the program.
Usage string
// Version of the program
Version string
// List of commands to execute
Commands []Command
// List of flags to parse
Flags []Flag
// Boolean to enable bash completion commands
EnableBashCompletion bool
// Boolean to hide built-in help command
HideHelp bool
// Boolean to hide built-in version flag
HideVersion bool
// An action to execute when the bash-completion flag is set
BashComplete func(context *Context)
// An action to execute before any subcommands are run, but after the context is ready
// If a non-nil error is returned, no subcommands are run
Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After func(context *Context) error
// The action to execute when no subcommands are specified
Action func(context *Context)
// Execute this function if the proper command cannot be found
CommandNotFound func(context *Context, command string)
// Compilation date
Compiled string
// ExtraInfo pass additional info as a key value map
ExtraInfo map[string]string
// List of all authors who contributed
Authors []Author
// Name of Author (Note: Use App.Authors, this is deprecated)
Author string
// Email of Author (Note: Use App.Authors, this is deprecated)
Email string
// Writer writer to write output to
Writer io.Writer
// CustomAppHelpTemplate the text template for app help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
CustomAppHelpTemplate string
}
// mustCompileTime - determines the modification time of the current binary
func mustCompileTime() string {
path, err := exec.LookPath(os.Args[0])
if err != nil {
return ""
}
info, err := os.Stat(path)
if err != nil {
return ""
}
return info.ModTime().String()
}
// NewApp - Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action.
func NewApp() *App {
return &App{
Name: os.Args[0],
Usage: "A new cli application",
Version: "0.0.0",
BashComplete: DefaultAppComplete,
Action: helpCommand.Action,
Compiled: mustCompileTime(),
Writer: os.Stdout,
}
}
// getNewContext -
func (a *App) getNewContext(arguments []string) (*Context, error) {
// parse flags
set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard)
context := NewContext(a, set, set)
err := set.Parse(arguments[1:])
if err != nil {
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
ShowAppHelp(context)
fmt.Fprintln(a.Writer)
return nil, err
}
nerr := normalizeFlags(a.Flags, set)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
ShowAppHelp(context)
fmt.Fprintln(a.Writer)
return nil, nerr
}
return context, nil
}
// Run - Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
func (a *App) Run(arguments []string) (err error) {
// Comment this out as its not going to be used
// if a.Author != "" || a.Email != "" {
// a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
//}
if HelpPrinter == nil {
defer func() {
HelpPrinter = nil
}()
HelpPrinter = func(templ string, data interface{}) {
funcMap := template.FuncMap{
"join": strings.Join,
}
w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0)
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
err := t.Execute(w, data)
if err != nil {
panic(err)
}
w.Flush()
}
}
// append help to commands
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand)
if (HelpFlag != BoolFlag{}) {
a.appendFlag(HelpFlag)
}
}
//append version/help flags
if a.EnableBashCompletion {
a.appendFlag(BashCompletionFlag)
}
if !a.HideVersion {
a.appendFlag(VersionFlag)
}
context, err := a.getNewContext(arguments)
if err != nil {
return err
}
if checkCompletions(context) || checkHelp(context) || checkVersion(context) {
return nil
}
if a.After != nil {
defer func() {
// err is always nil here.
// There is a check to see if it is non-nil
// just few lines before.
err = a.After(context)
}()
}
if a.Before != nil {
err := a.Before(context)
if err != nil {
return err
}
}
args := context.Args()
if args.Present() {
name := args.First()
c := a.Command(name)
if c != nil {
return c.Run(context)
}
}
// Run default Action
a.Action(context)
return nil
}
// RunAndExitOnError - Another entry point to the cli app, takes care of passing arguments and error handling
func (a *App) RunAndExitOnError() {
if err := a.Run(os.Args); err != nil {
os.Exit(1)
}
}
// RunAsSubcommand - Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
// append help to commands
if len(a.Commands) > 0 {
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand)
if (HelpFlag != BoolFlag{}) {
a.appendFlag(HelpFlag)
}
}
}
// append flags
if a.EnableBashCompletion {
a.appendFlag(BashCompletionFlag)
}
// parse flags
set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard)
err = set.Parse(ctx.Args().Tail())
nerr := normalizeFlags(a.Flags, set)
context := NewContext(a, set, ctx.globalSet)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
if len(a.Commands) > 0 {
ShowSubcommandHelp(context)
} else {
ShowCommandHelp(ctx, context.Args().First())
}
fmt.Fprintln(a.Writer)
return nerr
}
if err != nil {
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
ShowSubcommandHelp(context)
return err
}
if checkCompletions(context) {
return nil
}
if len(a.Commands) > 0 {
if checkSubcommandHelp(context) {
return nil
}
} else {
if checkCommandHelp(ctx, context.Args().First()) {
return nil
}
}
if a.After != nil {
defer func() {
// err is always nil here.
// There is a check to see if it is non-nil
// just few lines before.
err = a.After(context)
}()
}
if a.Before != nil {
err := a.Before(context)
if err != nil {
return err
}
}
args := context.Args()
if args.Present() {
name := args.First()
c := a.Command(name)
if c != nil {
return c.Run(context)
}
}
// Run default Action
a.Action(context)
return nil
}
// Command - Returns the named command on App. Returns nil if the command does not exist
func (a *App) Command(name string) *Command {
for _, c := range a.Commands {
if c.HasName(name) {
return &c
}
}
return nil
}
func (a *App) hasFlag(flag Flag) bool {
for _, f := range a.Flags {
if flag == f {
return true
}
}
return false
}
func (a *App) appendFlag(flag Flag) {
if !a.hasFlag(flag) {
a.Flags = append(a.Flags, flag)
}
}
// Author represents someone who has contributed to a cli project.
type Author struct {
Name string // The Authors name
Email string // The Authors email
}
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
func (a Author) String() string {
e := ""
if a.Email != "" {
e = "<" + a.Email + "> "
}
return fmt.Sprintf("%v %v", a.Name, e)
}
+587
View File
@@ -0,0 +1,587 @@
package cli_test
import (
"flag"
"fmt"
"os"
"testing"
"github.com/minio/cli"
)
func ExampleApp() {
// set args for examples sake
os.Args = []string{"greet", "--name", "Jeremy"}
app := cli.NewApp()
app.Name = "greet"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Action = func(c *cli.Context) {
fmt.Printf("Hello %v\n", c.String("name"))
}
app.Author = "Harrison"
app.Email = "harrison@lolwut.com"
app.Authors = []cli.Author{{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
app.Run(os.Args)
// Output:
// Hello Jeremy
}
func ExampleAppSubcommand() {
// set args for examples sake
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
app := cli.NewApp()
app.Name = "say"
app.Commands = []cli.Command{
{
Name: "hello",
Aliases: []string{"hi"},
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []cli.Command{
{
Name: "english",
Aliases: []string{"en"},
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *cli.Context) {
fmt.Println("Hello,", c.String("name"))
},
},
},
},
}
app.Run(os.Args)
// Output:
// Hello, Jeremy
}
func ExampleAppHelp() {
// set args for examples sake
os.Args = []string{"greet", "h", "describeit"}
app := cli.NewApp()
app.Name = "greet"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Commands = []cli.Command{
{
Name: "describeit",
Aliases: []string{"d"},
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) {
fmt.Printf("i like to describe things")
},
},
}
app.Run(os.Args)
// Output:
// NAME:
// describeit - use it to see a description
//
// USAGE:
// command describeit [arguments...]
//
// DESCRIPTION:
// This is how we describe describeit the function
}
func TestApp_Run(t *testing.T) {
s := ""
app := cli.NewApp()
app.Action = func(c *cli.Context) {
s = s + c.Args().First()
}
err := app.Run([]string{"command", "foo"})
expect(t, err, nil)
err = app.Run([]string{"command", "bar"})
expect(t, err, nil)
expect(t, s, "foobar")
}
var commandAppTests = []struct {
name string
expected bool
}{
{"foobar", true},
{"batbaz", true},
{"b", true},
{"f", true},
{"bat", false},
{"nothing", false},
}
func TestApp_Command(t *testing.T) {
app := cli.NewApp()
fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}}
batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}}
app.Commands = []cli.Command{
fooCommand,
batCommand,
}
for _, test := range commandAppTests {
expect(t, app.Command(test.name) != nil, test.expected)
}
}
func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
var parsedOption, firstArg string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *cli.Context) {
parsedOption = c.String("option")
firstArg = c.Args().First()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
expect(t, parsedOption, "my-option")
expect(t, firstArg, "my-arg")
}
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
var context *cli.Context
a := cli.NewApp()
a.Commands = []cli.Command{
{
Name: "foo",
Action: func(c *cli.Context) {
context = c
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
},
Before: func(_ *cli.Context) error { return nil },
},
}
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
expect(t, context.Args().Get(0), "abcd")
expect(t, context.String("lang"), "spanish")
}
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
var parsedOption string
var args []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *cli.Context) {
parsedOption = c.String("option")
args = c.Args()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
expect(t, parsedOption, "my-option")
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "--notARealFlag")
}
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
var args []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Action: func(c *cli.Context) {
args = c.Args()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "notAFlagAtAll")
}
func TestApp_Float64Flag(t *testing.T) {
var meters float64
app := cli.NewApp()
app.Flags = []cli.Flag{
cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
}
app.Action = func(c *cli.Context) {
meters = c.Float64("height")
}
app.Run([]string{"", "--height", "1.93"})
expect(t, meters, 1.93)
}
func TestApp_ParseSliceFlags(t *testing.T) {
var parsedOption, firstArg string
var parsedIntSlice []int
var parsedStringSlice []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"},
cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"},
},
Action: func(c *cli.Context) {
parsedIntSlice = c.IntSlice("p")
parsedStringSlice = c.StringSlice("ip")
parsedOption = c.String("option")
firstArg = c.Args().First()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
IntsEquals := func(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
StrsEquals := func(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
var expectedIntSlice = []int{22, 80}
var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
if !IntsEquals(parsedIntSlice, expectedIntSlice) {
t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
}
if !StrsEquals(parsedStringSlice, expectedStringSlice) {
t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
}
}
func TestApp_DefaultStdout(t *testing.T) {
app := cli.NewApp()
if app.Writer != os.Stdout {
t.Error("Default output writer not set.")
}
}
type mockWriter struct {
written []byte
}
func (fw *mockWriter) Write(p []byte) (n int, err error) {
if fw.written == nil {
fw.written = p
} else {
fw.written = append(fw.written, p...)
}
return len(p), nil
}
func (fw *mockWriter) GetWritten() (b []byte) {
return fw.written
}
func TestApp_SetStdout(t *testing.T) {
w := &mockWriter{}
app := cli.NewApp()
app.Name = "test"
app.Writer = w
err := app.Run([]string{"help"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if len(w.written) == 0 {
t.Error("App did not write output to desired writer.")
}
}
func TestApp_BeforeFunc(t *testing.T) {
beforeRun, subcommandRun := false, false
beforeError := fmt.Errorf("fail")
var err error
app := cli.NewApp()
app.Before = func(c *cli.Context) error {
beforeRun = true
s := c.String("opt")
if s == "fail" {
return beforeError
}
return nil
}
app.Commands = []cli.Command{
{
Name: "sub",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "opt"},
}
// run with the Before() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if beforeRun == false {
t.Errorf("Before() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
beforeRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != beforeError {
t.Errorf("Run error expected, but not received")
}
if beforeRun == false {
t.Errorf("Before() not executed when expected")
}
if subcommandRun == true {
t.Errorf("Subcommand executed when NOT expected")
}
}
func TestApp_AfterFunc(t *testing.T) {
afterRun, subcommandRun := false, false
afterError := fmt.Errorf("fail")
var err error
app := cli.NewApp()
app.After = func(c *cli.Context) error {
afterRun = true
s := c.String("opt")
if s == "fail" {
return afterError
}
return nil
}
app.Commands = []cli.Command{
{
Name: "sub",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "opt"},
}
// run with the After() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
afterRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != afterError {
t.Errorf("Run error expected, but not received")
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
}
func TestAppNoHelpFlag(t *testing.T) {
oldFlag := cli.HelpFlag
defer func() {
cli.HelpFlag = oldFlag
}()
cli.HelpFlag = cli.BoolFlag{}
app := cli.NewApp()
err := app.Run([]string{"test", "-h"})
if err != flag.ErrHelp {
t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
}
}
func TestAppHelpPrinter(t *testing.T) {
oldPrinter := cli.HelpPrinter
defer func() {
cli.HelpPrinter = oldPrinter
}()
var wasCalled = false
cli.HelpPrinter = func(template string, data interface{}) {
wasCalled = true
}
app := cli.NewApp()
app.Run([]string{"-h"})
if wasCalled == false {
t.Errorf("Help printer expected to be called, but was not")
}
}
func TestAppVersionPrinter(t *testing.T) {
oldPrinter := cli.VersionPrinter
defer func() {
cli.VersionPrinter = oldPrinter
}()
var wasCalled = false
cli.VersionPrinter = func(c *cli.Context) {
wasCalled = true
}
app := cli.NewApp()
ctx := cli.NewContext(app, nil, nil)
cli.ShowVersion(ctx)
if wasCalled == false {
t.Errorf("Version printer expected to be called, but was not")
}
}
func TestAppCommandNotFound(t *testing.T) {
beforeRun, subcommandRun := false, false
app := cli.NewApp()
app.CommandNotFound = func(c *cli.Context, command string) {
beforeRun = true
}
app.Commands = []cli.Command{
{
Name: "bar",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Run([]string{"command", "foo"})
expect(t, beforeRun, true)
expect(t, subcommandRun, false)
}
func TestGlobalFlagsInSubcommands(t *testing.T) {
subcommandRun := false
app := cli.NewApp()
app.Flags = []cli.Flag{
cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
}
app.Commands = []cli.Command{
{
Name: "foo",
Subcommands: []cli.Command{
{
Name: "bar",
Action: func(c *cli.Context) {
if c.GlobalBool("debug") {
subcommandRun = true
}
},
},
},
},
}
app.Run([]string{"command", "-d", "foo", "bar"})
expect(t, subcommandRun, true)
}
@@ -0,0 +1,13 @@
#! /bin/bash
_cli_bash_autocomplete() {
local cur prev opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -F _cli_bash_autocomplete $PROG
@@ -0,0 +1,5 @@
autoload -U compinit && compinit
autoload -U bashcompinit && bashcompinit
script_dir=$(dirname $0)
source ${script_dir}/bash_autocomplete
+93
View File
@@ -0,0 +1,93 @@
package cli
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
)
// BoolFlag - a flag of bool type
type BoolFlag struct {
Name string
Usage string
EnvVar string
Hide bool
}
// String -
func (f BoolFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
}
// Apply -
func (f BoolFlag) Apply(set *flag.FlagSet) {
val := false
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValBool, err := strconv.ParseBool(envVal)
if err == nil {
val = envValBool
}
break
}
}
}
eachName(f.Name, func(name string) {
set.Bool(name, val, f.Usage)
})
}
func (f BoolFlag) getName() string {
return f.Name
}
func (f BoolFlag) isNotHidden() bool {
return !f.Hide
}
// BoolTFlag - a flag of bool environment type
type BoolTFlag struct {
Name string
Usage string
EnvVar string
Hide bool
}
// String -
func (f BoolTFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
}
// Apply -
func (f BoolTFlag) Apply(set *flag.FlagSet) {
val := true
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValBool, err := strconv.ParseBool(envVal)
if err == nil {
val = envValBool
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Bool(name, val, f.Usage)
})
}
func (f BoolTFlag) getName() string {
return f.Name
}
func (f BoolTFlag) isNotHidden() bool {
return !f.Hide
}
+19
View File
@@ -0,0 +1,19 @@
// Package cli provides a minimal framework for creating and organizing command line
// Go applications. cli is designed to be easy to understand and write, the most simple
// cli application can be written as follows:
// func main() {
// cli.NewApp().Run(os.Args)
// }
//
// Of course this application does not do much, so let's make this an actual application:
// func main() {
// app := cli.NewApp()
// app.Name = "greet"
// app.Usage = "say a greeting"
// app.Action = func(c *cli.Context) {
// println("Greetings")
// }
//
// app.Run(os.Args)
// }
package cli
+100
View File
@@ -0,0 +1,100 @@
package cli_test
import (
"os"
"github.com/minio/cli"
)
func Example() {
app := cli.NewApp()
app.Name = "todo"
app.Usage = "task list on the command line"
app.Commands = []cli.Command{
{
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *cli.Context) {
println("added task: ", c.Args().First())
},
},
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
},
}
app.Run(os.Args)
}
func ExampleSubcommand() {
app := cli.NewApp()
app.Name = "say"
app.Commands = []cli.Command{
{
Name: "hello",
Aliases: []string{"hi"},
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []cli.Command{
{
Name: "english",
Aliases: []string{"en"},
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Hello, ", c.String("name"))
},
}, {
Name: "spanish",
Aliases: []string{"sp"},
Usage: "sends a greeting in spanish",
Flags: []cli.Flag{
cli.StringFlag{
Name: "surname",
Value: "Jones",
Usage: "Surname of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Hola, ", c.String("surname"))
},
}, {
Name: "french",
Aliases: []string{"fr"},
Usage: "sends a greeting in french",
Flags: []cli.Flag{
cli.StringFlag{
Name: "nickname",
Value: "Stevie",
Usage: "Nickname of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Bonjour, ", c.String("nickname"))
},
},
},
}, {
Name: "bye",
Usage: "says goodbye",
Action: func(c *cli.Context) {
println("bye")
},
},
}
app.Run(os.Args)
}
+187
View File
@@ -0,0 +1,187 @@
package cli
import (
"fmt"
"io/ioutil"
"strings"
)
// Command is a subcommand for a cli.App.
type Command struct {
// The name of the command
Name string
// short name of the command. Typically one character (deprecated, use `Aliases`)
ShortName string
// A list of aliases for the command
Aliases []string
// A short description of the usage of this command
Usage string
// A longer explanation of how the command works
Description string
// The function to call when checking for bash command completions
BashComplete func(context *Context)
// An action to execute before any sub-subcommands are run, but after the context is ready
// If a non-nil error is returned, no sub-subcommands are run
Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After func(context *Context) error
// The function to call when this command is invoked
Action func(context *Context)
// List of child commands
Subcommands []Command
// List of flags to parse
Flags []Flag
// Treat all flags as normal arguments if true
SkipFlagParsing bool
// Boolean to hide built-in help command
HideHelp bool
// Boolean to hide this command from help or completion
Hide bool
// CustomHelpTemplate the text template for the command help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
CustomHelpTemplate string
}
// Run - Invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) error {
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
return c.startApp(ctx)
}
if !c.HideHelp && (HelpFlag != BoolFlag{}) {
// append help to flags
c.Flags = append(
c.Flags,
HelpFlag,
)
}
if ctx.App.EnableBashCompletion {
c.Flags = append(c.Flags, BashCompletionFlag)
}
set := flagSet(c.Name, c.Flags)
set.SetOutput(ioutil.Discard)
firstFlagIndex := -1
terminatorIndex := -1
for index, arg := range ctx.Args() {
if arg == "--" {
terminatorIndex = index
break
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
firstFlagIndex = index
}
}
var err error
if firstFlagIndex > -1 && !c.SkipFlagParsing {
args := ctx.Args()
regularArgs := make([]string, len(args[1:firstFlagIndex]))
copy(regularArgs, args[1:firstFlagIndex])
var flagArgs []string
if terminatorIndex > -1 {
flagArgs = args[firstFlagIndex:terminatorIndex]
regularArgs = append(regularArgs, args[terminatorIndex:]...)
} else {
flagArgs = args[firstFlagIndex:]
}
err = set.Parse(append(flagArgs, regularArgs...))
} else {
err = set.Parse(ctx.Args().Tail())
}
if err != nil {
fmt.Fprint(ctx.App.Writer, "Incorrect Usage.\n\n")
ShowCommandHelp(ctx, c.Name)
fmt.Fprintln(ctx.App.Writer)
return err
}
nerr := normalizeFlags(c.Flags, set)
if nerr != nil {
fmt.Fprintln(ctx.App.Writer, nerr)
fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name)
fmt.Fprintln(ctx.App.Writer)
return nerr
}
context := NewContext(ctx.App, set, ctx.globalSet)
if checkCommandCompletions(context, c.Name) {
return nil
}
if checkCommandHelp(context, c.Name) {
return nil
}
context.Command = c
c.Action(context)
return nil
}
// Names - returns collection of all name, shortname and aliases
func (c Command) Names() []string {
names := []string{c.Name}
if c.ShortName != "" {
names = append(names, c.ShortName)
}
return append(names, c.Aliases...)
}
// HasName - Returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool {
for _, n := range c.Names() {
if n == name {
return true
}
}
return false
}
func (c Command) isNotHidden() bool {
return !c.Hide
}
func (c Command) startApp(ctx *Context) error {
app := NewApp()
// set the name and usage
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
if c.Description != "" {
app.Usage = c.Description
} else {
app.Usage = c.Usage
}
// set CommandNotFound
app.CommandNotFound = ctx.App.CommandNotFound
// set the flags and commands
app.Commands = c.Subcommands
app.Flags = c.Flags
app.HideHelp = c.HideHelp
// bash completion
app.EnableBashCompletion = ctx.App.EnableBashCompletion
if c.BashComplete != nil {
app.BashComplete = c.BashComplete
}
// set the actions
app.Before = c.Before
app.After = c.After
if c.Action != nil {
app.Action = c.Action
} else {
app.Action = helpSubcommand.Action
}
return app.RunAsSubcommand(ctx)
}
+49
View File
@@ -0,0 +1,49 @@
package cli_test
import (
"flag"
"testing"
"github.com/minio/cli"
)
func TestCommandDoNotIgnoreFlags(t *testing.T) {
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"blah", "blah", "-break"}
set.Parse(test)
c := cli.NewContext(app, set, set)
command := cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(_ *cli.Context) {},
}
err := command.Run(c)
expect(t, err.Error(), "flag provided but not defined: -break")
}
func TestCommandIgnoreFlags(t *testing.T) {
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"blah", "blah"}
set.Parse(test)
c := cli.NewContext(app, set, set)
command := cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(_ *cli.Context) {},
SkipFlagParsing: true,
}
err := command.Run(c)
expect(t, err, nil)
}
+350
View File
@@ -0,0 +1,350 @@
package cli
import (
"errors"
"flag"
"strconv"
"strings"
"time"
)
// Context is a type that is passed through to
// each Handler action in a cli application. Context
// can be used to retrieve context-specific Args and
// parsed command-line flags.
type Context struct {
App *App
Command Command
flagSet *flag.FlagSet
globalSet *flag.FlagSet
setFlags map[string]bool
globalSetFlags map[string]bool
}
// NewContext - Creates a new context. For use in when invoking an App or Command action.
func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context {
return &Context{App: app, flagSet: set, globalSet: globalSet}
}
// Int - Looks up the value of a local int flag, returns 0 if no int flag exists
func (c *Context) Int(name string) int {
return lookupInt(name, c.flagSet)
}
// Duration - Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists
func (c *Context) Duration(name string) time.Duration {
return lookupDuration(name, c.flagSet)
}
// Float64 - Looks up the value of a local float64 flag, returns 0 if no float64 flag exists
func (c *Context) Float64(name string) float64 {
return lookupFloat64(name, c.flagSet)
}
// Bool - Looks up the value of a local bool flag, returns false if no bool flag exists
func (c *Context) Bool(name string) bool {
return lookupBool(name, c.flagSet)
}
// BoolT - Looks up the value of a local boolT flag, returns false if no bool flag exists
func (c *Context) BoolT(name string) bool {
return lookupBoolT(name, c.flagSet)
}
// String Looks up the value of a local string flag, returns "" if no string flag exists
func (c *Context) String(name string) string {
return lookupString(name, c.flagSet)
}
// StringSlice - Looks up the value of a local string slice flag, returns nil if no string slice flag exists
func (c *Context) StringSlice(name string) []string {
return lookupStringSlice(name, c.flagSet)
}
// IntSlice - Looks up the value of a local int slice flag, returns nil if no int slice flag exists
func (c *Context) IntSlice(name string) []int {
return lookupIntSlice(name, c.flagSet)
}
// Generic - Looks up the value of a local generic flag, returns nil if no generic flag exists
func (c *Context) Generic(name string) interface{} {
return lookupGeneric(name, c.flagSet)
}
// GlobalInt - Looks up the value of a global int flag, returns 0 if no int flag exists
func (c *Context) GlobalInt(name string) int {
return lookupInt(name, c.globalSet)
}
// GlobalDuration - Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
func (c *Context) GlobalDuration(name string) time.Duration {
return lookupDuration(name, c.globalSet)
}
// GlobalBool - Looks up the value of a global bool flag, returns false if no bool flag exists
func (c *Context) GlobalBool(name string) bool {
return lookupBool(name, c.globalSet)
}
// GlobalString - Looks up the value of a global string flag, returns "" if no string flag exists
func (c *Context) GlobalString(name string) string {
return lookupString(name, c.globalSet)
}
// GlobalStringSlice - Looks up the value of a global string slice flag, returns nil if no string slice flag exists
func (c *Context) GlobalStringSlice(name string) []string {
return lookupStringSlice(name, c.globalSet)
}
// GlobalIntSlice - Looks up the value of a global int slice flag, returns nil if no int slice flag exists
func (c *Context) GlobalIntSlice(name string) []int {
return lookupIntSlice(name, c.globalSet)
}
// GlobalGeneric - Looks up the value of a global generic flag, returns nil if no generic flag exists
func (c *Context) GlobalGeneric(name string) interface{} {
return lookupGeneric(name, c.globalSet)
}
// NumFlags - Returns the number of flags set
func (c *Context) NumFlags() int {
return c.flagSet.NFlag()
}
// IsSet - Determines if the flag was actually set
func (c *Context) IsSet(name string) bool {
if c.setFlags == nil {
c.setFlags = make(map[string]bool)
c.flagSet.Visit(func(f *flag.Flag) {
c.setFlags[f.Name] = true
})
}
return c.setFlags[name] == true
}
// GlobalIsSet - Determines if the global flag was actually set
func (c *Context) GlobalIsSet(name string) bool {
if c.globalSetFlags == nil {
c.globalSetFlags = make(map[string]bool)
c.globalSet.Visit(func(f *flag.Flag) {
c.globalSetFlags[f.Name] = true
})
}
return c.globalSetFlags[name] == true
}
// FlagNames - Returns a slice of flag names used in this context.
func (c *Context) FlagNames() (names []string) {
for _, flag := range c.Command.Flags {
name := strings.Split(flag.getName(), ",")[0]
if name == "help" {
continue
}
names = append(names, name)
}
return
}
// GlobalFlagNames - Returns a slice of global flag names used by the app.
func (c *Context) GlobalFlagNames() (names []string) {
for _, flag := range c.App.Flags {
name := strings.Split(flag.getName(), ",")[0]
if name == "help" || name == "version" {
continue
}
names = append(names, name)
}
return
}
// Args - slice of string
type Args []string
// Args - Returns the command line arguments associated with the context.
func (c *Context) Args() Args {
args := Args(c.flagSet.Args())
return args
}
// Get - Returns the nth argument, or else a blank string
func (a Args) Get(n int) string {
if len(a) > n {
return a[n]
}
return ""
}
// First - Returns the first argument, or else a blank string
func (a Args) First() string {
return a.Get(0)
}
// Last - Return the last argument, or else a blank String
func (a Args) Last() string {
return a.Get(len(a) - 1)
}
// Tail - Return the rest of the arguments (not the first one)
// or else an empty string slice
func (a Args) Tail() Args {
if len(a) >= 2 {
return []string(a)[1:]
}
return []string{}
}
// Present - Checks if there are any arguments present
func (a Args) Present() bool {
return len(a) != 0
}
// Swap - swaps arguments at the given indexes
func (a Args) Swap(from, to int) error {
if from >= len(a) || to >= len(a) {
return errors.New("index out of range")
}
a[from], a[to] = a[to], a[from]
return nil
}
func lookupInt(name string, set *flag.FlagSet) int {
f := set.Lookup(name)
if f != nil {
val, err := strconv.Atoi(f.Value.String())
if err != nil {
return 0
}
return val
}
return 0
}
func lookupDuration(name string, set *flag.FlagSet) time.Duration {
f := set.Lookup(name)
if f != nil {
val, err := time.ParseDuration(f.Value.String())
if err == nil {
return val
}
}
return 0
}
func lookupFloat64(name string, set *flag.FlagSet) float64 {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseFloat(f.Value.String(), 64)
if err != nil {
return 0
}
return val
}
return 0
}
func lookupString(name string, set *flag.FlagSet) string {
f := set.Lookup(name)
if f != nil {
return f.Value.String()
}
return ""
}
func lookupStringSlice(name string, set *flag.FlagSet) []string {
f := set.Lookup(name)
if f != nil {
return (f.Value.(*StringSlice)).Value()
}
return nil
}
func lookupIntSlice(name string, set *flag.FlagSet) []int {
f := set.Lookup(name)
if f != nil {
return (f.Value.(*IntSlice)).Value()
}
return nil
}
func lookupGeneric(name string, set *flag.FlagSet) interface{} {
f := set.Lookup(name)
if f != nil {
return f.Value
}
return nil
}
func lookupBool(name string, set *flag.FlagSet) bool {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseBool(f.Value.String())
if err != nil {
return false
}
return val
}
return false
}
func lookupBoolT(name string, set *flag.FlagSet) bool {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseBool(f.Value.String())
if err != nil {
return true
}
return val
}
return false
}
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
switch ff.Value.(type) {
case *StringSlice:
default:
set.Set(name, ff.Value.String())
}
}
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
visited := make(map[string]bool)
set.Visit(func(f *flag.Flag) {
visited[f.Name] = true
})
for _, f := range flags {
parts := strings.Split(f.getName(), ",")
if len(parts) == 1 {
continue
}
var ff *flag.Flag
for _, name := range parts {
name = strings.Trim(name, " ")
if visited[name] {
if ff != nil {
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
}
ff = set.Lookup(name)
}
}
if ff == nil {
continue
}
for _, name := range parts {
name = strings.Trim(name, " ")
if !visited[name] {
copyFlag(name, ff, set)
}
}
}
return nil
}
+111
View File
@@ -0,0 +1,111 @@
package cli_test
import (
"flag"
"testing"
"time"
"github.com/minio/cli"
)
func TestNewContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Int("myflag", 42, "doc")
command := cli.Command{Name: "mycommand"}
c := cli.NewContext(nil, set, globalSet)
c.Command = command
expect(t, c.Int("myflag"), 12)
expect(t, c.GlobalInt("myflag"), 42)
expect(t, c.Command.Name, "mycommand")
}
func TestContext_Int(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Int("myflag"), 12)
}
func TestContext_Duration(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Duration("myflag", time.Duration(12*time.Second), "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
}
func TestContext_String(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.String("myflag", "hello world", "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.String("myflag"), "hello world")
}
func TestContext_Bool(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Bool("myflag"), false)
}
func TestContext_BoolT(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", true, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.BoolT("myflag"), true)
}
func TestContext_Args(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
c := cli.NewContext(nil, set, set)
set.Parse([]string{"--myflag", "bat", "baz"})
expect(t, len(c.Args()), 2)
expect(t, c.Bool("myflag"), true)
}
func TestContext_IsSet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "bat", "baz"})
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
expect(t, c.IsSet("myflag"), true)
expect(t, c.IsSet("otherflag"), false)
expect(t, c.IsSet("bogusflag"), false)
expect(t, c.IsSet("myflagGlobal"), false)
}
func TestContext_GlobalIsSet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
globalSet.Bool("myflagGlobalUnset", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "bat", "baz"})
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
expect(t, c.GlobalIsSet("myflag"), false)
expect(t, c.GlobalIsSet("otherflag"), false)
expect(t, c.GlobalIsSet("bogusflag"), false)
expect(t, c.GlobalIsSet("myflagGlobal"), true)
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
expect(t, c.GlobalIsSet("bogusGlobal"), false)
}
func TestContext_NumFlags(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "--otherflag=foo"})
globalSet.Parse([]string{"--myflagGlobal"})
expect(t, c.NumFlags(), 2)
}
+51
View File
@@ -0,0 +1,51 @@
package cli
import (
"flag"
"fmt"
"os"
"strings"
"time"
)
// DurationFlag - a flag of time.Duration type
type DurationFlag struct {
Name string
Value time.Duration
Usage string
EnvVar string
Hide bool
}
// String -
func (f DurationFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply -
func (f DurationFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValDuration, err := time.ParseDuration(envVal)
if err == nil {
f.Value = envValDuration
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Duration(name, f.Value, f.Usage)
})
}
func (f DurationFlag) getName() string {
return f.Name
}
func (f DurationFlag) isNotHidden() bool {
return !f.Hide
}
+137
View File
@@ -0,0 +1,137 @@
package cli
import (
"flag"
"fmt"
"os"
"strings"
)
// BashCompletionFlag - This flag enables bash-completion for all commands and subcommands
// it is hidden by default
var BashCompletionFlag = BoolFlag{
Name: "generate-bash-completion",
Hide: true,
}
// VersionFlag - This flag prints the version for the application
var VersionFlag = BoolFlag{
Name: "version, v",
Usage: "print the version",
}
// HelpFlay - This flag prints the help for all commands and subcommands
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
// unless HideHelp is set to true) it is hidden by default
var HelpFlag = BoolFlag{
Name: "help, h",
Usage: "show help",
Hide: true,
}
// Flag is a common interface related to parsing flags in cli.
// For more advanced flag parsing techniques, it is recomended that
// this interface be implemented.
type Flag interface {
fmt.Stringer
// Apply Flag settings to the given flag set
Apply(*flag.FlagSet)
getName() string
isNotHidden() bool
}
func flagSet(name string, flags []Flag) *flag.FlagSet {
set := flag.NewFlagSet(name, flag.ContinueOnError)
for _, f := range flags {
f.Apply(set)
}
return set
}
func eachName(longName string, fn func(string)) {
parts := strings.Split(longName, ",")
for _, name := range parts {
name = strings.Trim(name, " ")
fn(name)
}
}
// Generic is a generic parseable type identified by a specific flag
type Generic interface {
Set(value string) error
String() string
}
// GenericFlag is the flag type for types implementing Generic
type GenericFlag struct {
Name string
Value Generic
Usage string
EnvVar string
Hide bool
}
// String returns the string representation of the generic flag to display the
// help text to the user (uses the String() method of the generic flag to show
// the value)
func (f GenericFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
}
// Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag
func (f GenericFlag) Apply(set *flag.FlagSet) {
val := f.Value
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
val.Set(envVal)
break
}
}
}
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f GenericFlag) getName() string {
return f.Name
}
func (f GenericFlag) isNotHidden() bool {
return !f.Hide
}
func prefixFor(name string) (prefix string) {
if len(name) == 1 {
prefix = "-"
} else {
prefix = "--"
}
return
}
func prefixedNames(fullName string) (prefixed string) {
parts := strings.Split(fullName, ",")
for i, name := range parts {
name = strings.Trim(name, " ")
prefixed += prefixFor(name) + name
if i < len(parts)-1 {
prefixed += ", "
}
}
return
}
func withEnvHint(envVar, str string) string {
envText := ""
if envVar != "" {
envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
}
return str + envText
}
+742
View File
@@ -0,0 +1,742 @@
package cli_test
import (
"fmt"
"os"
"reflect"
"strings"
"testing"
"github.com/minio/cli"
)
var boolFlagTests = []struct {
name string
expected string
}{
{"help", "--help\t"},
{"h", "-h\t"},
}
func TestBoolFlagHelpOutput(t *testing.T) {
for _, test := range boolFlagTests {
flag := cli.BoolFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
var stringFlagTests = []struct {
name string
value string
expected string
}{
{"help", "", "--help \t"},
{"h", "", "-h \t"},
{"h", "", "-h \t"},
{"test", "Something", "--test \"Something\"\t"},
}
func TestStringFlagHelpOutput(t *testing.T) {
for _, test := range stringFlagTests {
flag := cli.StringFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "derp")
for _, test := range stringFlagTests {
flag := cli.StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_FOO]") {
t.Errorf("%s does not end with [$APP_FOO]", output)
}
}
}
var stringSliceFlagTests = []struct {
name string
value *cli.StringSlice
expected string
}{
{"help", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "--help [--help option --help option]\t"},
{"h", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "-h [-h option -h option]\t"},
{"h", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "-h [-h option -h option]\t"},
{"test", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("Something")
return s
}(), "--test [--test option --test option]\t"},
}
func TestStringSliceFlagHelpOutput(t *testing.T) {
for _, test := range stringSliceFlagTests {
flag := cli.StringSliceFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_QWWX", "11,4")
for _, test := range stringSliceFlagTests {
flag := cli.StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_QWWX]") {
t.Errorf("%q does not end with [$APP_QWWX]", output)
}
}
}
var intFlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestIntFlagHelpOutput(t *testing.T) {
for _, test := range intFlagTests {
flag := cli.IntFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2")
for _, test := range intFlagTests {
flag := cli.IntFlag{Name: test.name, EnvVar: "APP_BAR"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAR]") {
t.Errorf("%s does not end with [$APP_BAR]", output)
}
}
}
var durationFlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestDurationFlagHelpOutput(t *testing.T) {
for _, test := range durationFlagTests {
flag := cli.DurationFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2h3m6s")
for _, test := range durationFlagTests {
flag := cli.DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAR]") {
t.Errorf("%s does not end with [$APP_BAR]", output)
}
}
}
var intSliceFlagTests = []struct {
name string
value *cli.IntSlice
expected string
}{
{"help", &cli.IntSlice{}, "--help [--help option --help option]\t"},
{"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
{"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
{"test", func() *cli.IntSlice {
i := &cli.IntSlice{}
i.Set("9")
return i
}(), "--test [--test option --test option]\t"},
}
func TestIntSliceFlagHelpOutput(t *testing.T) {
for _, test := range intSliceFlagTests {
flag := cli.IntSliceFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SMURF", "42,3")
for _, test := range intSliceFlagTests {
flag := cli.IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_SMURF]") {
t.Errorf("%q does not end with [$APP_SMURF]", output)
}
}
}
var float64FlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestFloat64FlagHelpOutput(t *testing.T) {
for _, test := range float64FlagTests {
flag := cli.Float64Flag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAZ", "99.4")
for _, test := range float64FlagTests {
flag := cli.Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAZ]") {
t.Errorf("%s does not end with [$APP_BAZ]", output)
}
}
}
var genericFlagTests = []struct {
name string
value cli.Generic
expected string
}{
{"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"},
{"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"},
}
func TestGenericFlagHelpOutput(t *testing.T) {
for _, test := range genericFlagTests {
flag := cli.GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_ZAP", "3")
for _, test := range genericFlagTests {
flag := cli.GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_ZAP]") {
t.Errorf("%s does not end with [$APP_ZAP]", output)
}
}
}
func TestParseMultiString(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.String("serve") != "10" {
t.Errorf("main name not set")
}
if ctx.String("s") != "10" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10"})
}
func TestParseMultiStringFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
},
Action: func(ctx *cli.Context) {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
},
Action: func(ctx *cli.Context) {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringSlice(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "serve, s", Value: &cli.StringSlice{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiStringSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiInt(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("serve") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("s") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10"})
}
func TestParseMultiIntFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntSlice(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "serve, s", Value: &cli.IntSlice{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiIntSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiFloat64(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("serve") != 10.2 {
t.Errorf("main name not set")
}
if ctx.Float64("s") != 10.2 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10.2"})
}
func TestParseMultiFloat64FromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBool(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("serve") != true {
t.Errorf("main name not set")
}
if ctx.Bool("s") != true {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseMultiBoolFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolT(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("serve") != true {
t.Errorf("main name not set")
}
if ctx.BoolT("s") != true {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseMultiBoolTFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.BoolT("d") != false {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.BoolT("d") != false {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
type Parser [2]string
func (p *Parser) Set(value string) error {
parts := strings.Split(value, ",")
if len(parts) != 2 {
return fmt.Errorf("invalid format")
}
(*p)[0] = parts[0]
(*p)[1] = parts[1]
return nil
}
func (p *Parser) String() string {
return fmt.Sprintf("%s,%s", p[0], p[1])
}
func TestParseGeneric(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "serve, s", Value: &Parser{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10,20"})
}
func TestParseGenericFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SERVE", "20,30")
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseGenericFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "99,2000")
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
t.Errorf("value not set from env")
}
},
}
a.Run([]string{"run"})
}
+50
View File
@@ -0,0 +1,50 @@
package cli
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
)
// Float64Flag - a flag of floating number type
type Float64Flag struct {
Name string
Value float64
Usage string
EnvVar string
Hide bool
}
// String -
func (f Float64Flag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply -
func (f Float64Flag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValFloat, err := strconv.ParseFloat(envVal, 10)
if err == nil {
f.Value = float64(envValFloat)
}
}
}
}
eachName(f.Name, func(name string) {
set.Float64(name, f.Value, f.Usage)
})
}
func (f Float64Flag) getName() string {
return f.Name
}
func (f Float64Flag) isNotHidden() bool {
return !f.Hide
}
+275
View File
@@ -0,0 +1,275 @@
package cli
import (
"fmt"
"os"
)
// The text template for the Default help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var DefaultAppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.Name}} {{if .Flags}}[global flags] {{end}}command{{if .Flags}} [command flags]{{end}} [arguments...]
COMMANDS:
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}}
GLOBAL FLAGS:
{{range .Flags}}{{.}}
{{end}}{{end}}
VERSION:
{{.Version}}
{{if .Compiled}}
BUILD:
{{.Compiled}}{{end}}
{{range $key, $value := .ExtraInfo}}
{{$value}}{{end}}
`
// The text template for the command help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var DefaultCommandHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
command {{.Name}}{{if .Flags}} [command flags]{{end}} [arguments...]{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if .Flags}}
FLAGS:
{{range .Flags}}{{.}}
{{end}}{{ end }}
`
// The text template for the subcommand help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var DefaultSubcommandHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.Name}} command{{if .Flags}} [command flags]{{end}} [arguments...]
COMMANDS:
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}}
FLAGS:
{{range .Flags}}{{.}}
{{end}}{{end}}
`
var helpCommand = Command{
Name: "help",
Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command",
Action: func(c *Context) {
args := c.Args()
if args.Present() {
ShowCommandHelp(c, args.First())
} else {
ShowAppHelp(c)
}
},
Hide: true,
}
var helpSubcommand = Command{
Name: "help",
Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command",
Action: func(c *Context) {
args := c.Args()
if args.Present() {
ShowCommandHelp(c, args.First())
} else {
ShowSubcommandHelp(c)
}
},
Hide: true,
}
// Prints help for the App
type helpPrinter func(templ string, data interface{})
// HelpPrinter - prints help for the app
var HelpPrinter helpPrinter
// Prints version for the App
var VersionPrinter = printVersion
// ShowAppHelp - Prints the list of subcommands for the app
func ShowAppHelp(c *Context) {
// Make a copy of c.App context
app := *c.App
app.Flags = make([]Flag, 0)
app.Commands = make([]Command, 0)
for _, flag := range c.App.Flags {
if flag.isNotHidden() {
app.Flags = append(app.Flags, flag)
}
}
for _, command := range c.App.Commands {
if command.isNotHidden() {
app.Commands = append(app.Commands, command)
}
}
if app.CustomAppHelpTemplate != "" {
HelpPrinter(app.CustomAppHelpTemplate, app)
} else {
HelpPrinter(DefaultAppHelpTemplate, app)
}
}
// DefaultAppComplete - Prints the list of subcommands as the default app completion method
func DefaultAppComplete(c *Context) {
for _, command := range c.App.Commands {
if command.isNotHidden() {
for _, name := range command.Names() {
fmt.Fprintln(c.App.Writer, name)
}
}
}
}
// ShowCommandHelpAndExit - exits with code after showing help
func ShowCommandHelpAndExit(c *Context, command string, code int) {
ShowCommandHelp(c, command)
os.Exit(code)
}
// ShowCommandHelp - Prints help for the given command
func ShowCommandHelp(c *Context, command string) {
// show the subcommand help for a command with subcommands
if command == "" {
// Make a copy of c.App context
app := *c.App
app.Flags = make([]Flag, 0)
app.Commands = make([]Command, 0)
for _, flag := range c.App.Flags {
if flag.isNotHidden() {
app.Flags = append(app.Flags, flag)
}
}
for _, command := range c.App.Commands {
if command.isNotHidden() {
app.Commands = append(app.Commands, command)
}
}
HelpPrinter(DefaultSubcommandHelpTemplate, app)
return
}
for _, c := range c.App.Commands {
if c.HasName(command) {
// Make a copy of command context
c0 := c
c0.Flags = make([]Flag, 0)
for _, flag := range c.Flags {
if flag.isNotHidden() {
c0.Flags = append(c0.Flags, flag)
}
}
if c0.CustomHelpTemplate != "" {
HelpPrinter(c0.CustomHelpTemplate, c0)
} else {
HelpPrinter(DefaultCommandHelpTemplate, c0)
}
return
}
}
if c.App.CommandNotFound != nil {
c.App.CommandNotFound(c, command)
} else {
fmt.Fprintf(c.App.Writer, "No help topic for '%v'\n", command)
}
}
// ShowSubcommandHelp - Prints help for the given subcommand
func ShowSubcommandHelp(c *Context) {
ShowCommandHelp(c, c.Command.Name)
}
// ShowVersion - Prints the version number of the App
func ShowVersion(c *Context) {
VersionPrinter(c)
}
func printVersion(c *Context) {
fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
}
// ShowCompletions - Prints the lists of commands within a given context
func ShowCompletions(c *Context) {
a := c.App
if a != nil && a.BashComplete != nil {
a.BashComplete(c)
}
}
// ShowCommandCompletions - Prints the custom completions for a given command
func ShowCommandCompletions(ctx *Context, command string) {
c := ctx.App.Command(command)
if c != nil && c.BashComplete != nil {
c.BashComplete(ctx)
}
}
func checkVersion(c *Context) bool {
if c.GlobalBool("version") {
ShowVersion(c)
return true
}
return false
}
func checkHelp(c *Context) bool {
if c.GlobalBool("h") || c.GlobalBool("help") {
ShowAppHelp(c)
return true
}
return false
}
func checkCommandHelp(c *Context, name string) bool {
if c.Bool("h") || c.Bool("help") {
ShowCommandHelp(c, name)
return true
}
return false
}
func checkSubcommandHelp(c *Context) bool {
if c.GlobalBool("h") || c.GlobalBool("help") {
ShowSubcommandHelp(c)
return true
}
return false
}
func checkCompletions(c *Context) bool {
if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion {
ShowCompletions(c)
return true
}
return false
}
func checkCommandCompletions(c *Context, name string) bool {
if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion {
ShowCommandCompletions(c, name)
return true
}
return false
}
+19
View File
@@ -0,0 +1,19 @@
package cli_test
import (
"reflect"
"testing"
)
/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func refute(t *testing.T, a interface{}, b interface{}) {
if a == b {
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
+51
View File
@@ -0,0 +1,51 @@
package cli
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
)
// IntFlag - a flag of integer type
type IntFlag struct {
Name string
Value int
Usage string
EnvVar string
Hide bool
}
// String -
func (f IntFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply -
func (f IntFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValInt, err := strconv.ParseInt(envVal, 0, 64)
if err == nil {
f.Value = int(envValInt)
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Int(name, f.Value, f.Usage)
})
}
func (f IntFlag) getName() string {
return f.Name
}
func (f IntFlag) isNotHidden() bool {
return !f.Hide
}
+81
View File
@@ -0,0 +1,81 @@
package cli
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
)
// IntSlice - a type of integer slice
type IntSlice []int
// Set -
func (f *IntSlice) Set(value string) error {
tmp, err := strconv.Atoi(value)
if err != nil {
return err
}
*f = append(*f, tmp)
return nil
}
// String -
func (f *IntSlice) String() string {
return fmt.Sprintf("%d", *f)
}
// Value -
func (f *IntSlice) Value() []int {
return *f
}
// IntSliceFlag - a type of integer slice flag
type IntSliceFlag struct {
Name string
Value *IntSlice
Usage string
EnvVar string
Hide bool
}
// String -
func (f IntSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
}
// Apply -
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
newVal := &IntSlice{}
for _, s := range strings.Split(envVal, ",") {
s = strings.TrimSpace(s)
err := newVal.Set(s)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
}
}
f.Value = newVal
break
}
}
}
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f IntSliceFlag) getName() string {
return f.Name
}
func (f IntSliceFlag) isNotHidden() bool {
return !f.Hide
}
+54
View File
@@ -0,0 +1,54 @@
package cli
import (
"flag"
"fmt"
"os"
"strings"
)
// StringFlag - a string flag type
type StringFlag struct {
Name string
Value string
Usage string
EnvVar string
Hide bool
}
func (f StringFlag) String() string {
var fmtString string
fmtString = "%s %v\t%v"
if len(f.Value) > 0 {
fmtString = "%s \"%v\"\t%v"
} else {
fmtString = "%s %v\t%v"
}
return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply -
func (f StringFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
f.Value = envVal
break
}
}
}
eachName(f.Name, func(name string) {
set.String(name, f.Value, f.Usage)
})
}
func (f StringFlag) getName() string {
return f.Name
}
func (f StringFlag) isNotHidden() bool {
return !f.Hide
}
+73
View File
@@ -0,0 +1,73 @@
package cli
import (
"flag"
"fmt"
"os"
"strings"
)
// StringSlice - type
type StringSlice []string
// Set -
func (f *StringSlice) Set(value string) error {
*f = append(*f, value)
return nil
}
// String -
func (f *StringSlice) String() string {
return fmt.Sprintf("%s", *f)
}
// Value -
func (f *StringSlice) Value() []string {
return *f
}
// StringSliceFlag - a string slice flag type
type StringSliceFlag struct {
Name string
Value *StringSlice
Usage string
EnvVar string
Hide bool
}
// String -
func (f StringSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
}
// Apply -
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
newVal := &StringSlice{}
for _, s := range strings.Split(envVal, ",") {
s = strings.TrimSpace(s)
newVal.Set(s)
}
f.Value = newVal
break
}
}
}
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f StringSliceFlag) getName() string {
return f.Name
}
func (f StringSliceFlag) isNotHidden() bool {
return !f.Hide
}
@@ -0,0 +1,22 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
+23
View File
@@ -0,0 +1,23 @@
objx - by Mat Ryer and Tyler Bunnell
The MIT License (MIT)
Copyright (c) 2014 Stretchr, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+3
View File
@@ -0,0 +1,3 @@
# objx
* Jump into the [API Documentation](http://godoc.org/github.com/stretchr/objx)
+179
View File
@@ -0,0 +1,179 @@
package objx
import (
"fmt"
"regexp"
"strconv"
"strings"
)
// arrayAccesRegexString is the regex used to extract the array number
// from the access path
const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
// arrayAccesRegex is the compiled arrayAccesRegexString
var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
// Get gets the value using the specified selector and
// returns it inside a new Obj object.
//
// If it cannot find the value, Get will return a nil
// value inside an instance of Obj.
//
// Get can only operate directly on map[string]interface{} and []interface.
//
// Example
//
// To access the title of the third chapter of the second book, do:
//
// o.Get("books[1].chapters[2].title")
func (m Map) Get(selector string) *Value {
rawObj := access(m, selector, nil, false, false)
return &Value{data: rawObj}
}
// Set sets the value using the specified selector and
// returns the object on which Set was called.
//
// Set can only operate directly on map[string]interface{} and []interface
//
// Example
//
// To set the title of the third chapter of the second book, do:
//
// o.Set("books[1].chapters[2].title","Time to Go")
func (m Map) Set(selector string, value interface{}) Map {
access(m, selector, value, true, false)
return m
}
// access accesses the object using the selector and performs the
// appropriate action.
func access(current, selector, value interface{}, isSet, panics bool) interface{} {
switch selector.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
if array, ok := current.([]interface{}); ok {
index := intFromInterface(selector)
if index >= len(array) {
if panics {
panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
}
return nil
}
return array[index]
}
return nil
case string:
selStr := selector.(string)
selSegs := strings.SplitN(selStr, PathSeparator, 2)
thisSel := selSegs[0]
index := -1
var err error
// https://github.com/stretchr/objx/issues/12
if strings.Contains(thisSel, "[") {
arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
if len(arrayMatches) > 0 {
// Get the key into the map
thisSel = arrayMatches[1]
// Get the index into the array at the key
index, err = strconv.Atoi(arrayMatches[2])
if err != nil {
// This should never happen. If it does, something has gone
// seriously wrong. Panic.
panic("objx: Array index is not an integer. Must use array[int].")
}
}
}
if curMap, ok := current.(Map); ok {
current = map[string]interface{}(curMap)
}
// get the object in question
switch current.(type) {
case map[string]interface{}:
curMSI := current.(map[string]interface{})
if len(selSegs) <= 1 && isSet {
curMSI[thisSel] = value
return nil
} else {
current = curMSI[thisSel]
}
default:
current = nil
}
if current == nil && panics {
panic(fmt.Sprintf("objx: '%v' invalid on object.", selector))
}
// do we need to access the item of an array?
if index > -1 {
if array, ok := current.([]interface{}); ok {
if index < len(array) {
current = array[index]
} else {
if panics {
panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
}
current = nil
}
}
}
if len(selSegs) > 1 {
current = access(current, selSegs[1], value, isSet, panics)
}
}
return current
}
// intFromInterface converts an interface object to the largest
// representation of an unsigned integer using a type switch and
// assertions
func intFromInterface(selector interface{}) int {
var value int
switch selector.(type) {
case int:
value = selector.(int)
case int8:
value = int(selector.(int8))
case int16:
value = int(selector.(int16))
case int32:
value = int(selector.(int32))
case int64:
value = int(selector.(int64))
case uint:
value = int(selector.(uint))
case uint8:
value = int(selector.(uint8))
case uint16:
value = int(selector.(uint16))
case uint32:
value = int(selector.(uint32))
case uint64:
value = int(selector.(uint64))
default:
panic("objx: array access argument is not an integer type (this should never happen)")
}
return value
}
+145
View File
@@ -0,0 +1,145 @@
package objx
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestAccessorsAccessGetSingleField(t *testing.T) {
current := map[string]interface{}{"name": "Tyler"}
assert.Equal(t, "Tyler", access(current, "name", nil, false, true))
}
func TestAccessorsAccessGetDeep(t *testing.T) {
current := map[string]interface{}{"name": map[string]interface{}{"first": "Tyler", "last": "Bunnell"}}
assert.Equal(t, "Tyler", access(current, "name.first", nil, false, true))
assert.Equal(t, "Bunnell", access(current, "name.last", nil, false, true))
}
func TestAccessorsAccessGetDeepDeep(t *testing.T) {
current := map[string]interface{}{"one": map[string]interface{}{"two": map[string]interface{}{"three": map[string]interface{}{"four": 4}}}}
assert.Equal(t, 4, access(current, "one.two.three.four", nil, false, true))
}
func TestAccessorsAccessGetInsideArray(t *testing.T) {
current := map[string]interface{}{"names": []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}}
assert.Equal(t, "Tyler", access(current, "names[0].first", nil, false, true))
assert.Equal(t, "Bunnell", access(current, "names[0].last", nil, false, true))
assert.Equal(t, "Capitol", access(current, "names[1].first", nil, false, true))
assert.Equal(t, "Bollocks", access(current, "names[1].last", nil, false, true))
assert.Panics(t, func() {
access(current, "names[2]", nil, false, true)
})
assert.Nil(t, access(current, "names[2]", nil, false, false))
}
func TestAccessorsAccessGetFromArrayWithInt(t *testing.T) {
current := []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}
one := access(current, 0, nil, false, false)
two := access(current, 1, nil, false, false)
three := access(current, 2, nil, false, false)
assert.Equal(t, "Tyler", one.(map[string]interface{})["first"])
assert.Equal(t, "Capitol", two.(map[string]interface{})["first"])
assert.Nil(t, three)
}
func TestAccessorsGet(t *testing.T) {
current := New(map[string]interface{}{"name": "Tyler"})
assert.Equal(t, "Tyler", current.Get("name").data)
}
func TestAccessorsAccessSetSingleField(t *testing.T) {
current := map[string]interface{}{"name": "Tyler"}
access(current, "name", "Mat", true, false)
assert.Equal(t, current["name"], "Mat")
access(current, "age", 29, true, true)
assert.Equal(t, current["age"], 29)
}
func TestAccessorsAccessSetSingleFieldNotExisting(t *testing.T) {
current := map[string]interface{}{}
access(current, "name", "Mat", true, false)
assert.Equal(t, current["name"], "Mat")
}
func TestAccessorsAccessSetDeep(t *testing.T) {
current := map[string]interface{}{"name": map[string]interface{}{"first": "Tyler", "last": "Bunnell"}}
access(current, "name.first", "Mat", true, true)
access(current, "name.last", "Ryer", true, true)
assert.Equal(t, "Mat", access(current, "name.first", nil, false, true))
assert.Equal(t, "Ryer", access(current, "name.last", nil, false, true))
}
func TestAccessorsAccessSetDeepDeep(t *testing.T) {
current := map[string]interface{}{"one": map[string]interface{}{"two": map[string]interface{}{"three": map[string]interface{}{"four": 4}}}}
access(current, "one.two.three.four", 5, true, true)
assert.Equal(t, 5, access(current, "one.two.three.four", nil, false, true))
}
func TestAccessorsAccessSetArray(t *testing.T) {
current := map[string]interface{}{"names": []interface{}{"Tyler"}}
access(current, "names[0]", "Mat", true, true)
assert.Equal(t, "Mat", access(current, "names[0]", nil, false, true))
}
func TestAccessorsAccessSetInsideArray(t *testing.T) {
current := map[string]interface{}{"names": []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}}
access(current, "names[0].first", "Mat", true, true)
access(current, "names[0].last", "Ryer", true, true)
access(current, "names[1].first", "Captain", true, true)
access(current, "names[1].last", "Underpants", true, true)
assert.Equal(t, "Mat", access(current, "names[0].first", nil, false, true))
assert.Equal(t, "Ryer", access(current, "names[0].last", nil, false, true))
assert.Equal(t, "Captain", access(current, "names[1].first", nil, false, true))
assert.Equal(t, "Underpants", access(current, "names[1].last", nil, false, true))
}
func TestAccessorsAccessSetFromArrayWithInt(t *testing.T) {
current := []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}
one := access(current, 0, nil, false, false)
two := access(current, 1, nil, false, false)
three := access(current, 2, nil, false, false)
assert.Equal(t, "Tyler", one.(map[string]interface{})["first"])
assert.Equal(t, "Capitol", two.(map[string]interface{})["first"])
assert.Nil(t, three)
}
func TestAccessorsSet(t *testing.T) {
current := New(map[string]interface{}{"name": "Tyler"})
current.Set("name", "Mat")
assert.Equal(t, "Mat", current.Get("name").data)
}
@@ -0,0 +1,14 @@
case []{1}:
a := object.([]{1})
if isSet {
a[index] = value.({1})
} else {
if index >= len(a) {
if panics {
panic(fmt.Sprintf("objx: Index %d is out of range because the []{1} only contains %d items.", index, len(a)))
}
return nil
} else {
return a[index]
}
}
+86
View File
@@ -0,0 +1,86 @@
<html>
<head>
<title>
Codegen
</title>
<style>
body {
width: 800px;
margin: auto;
}
textarea {
width: 100%;
min-height: 100px;
font-family: Courier;
}
</style>
</head>
<body>
<h2>
Template
</h2>
<p>
Use <code>{x}</code> as a placeholder for each argument.
</p>
<textarea id="template"></textarea>
<h2>
Arguments (comma separated)
</h2>
<p>
One block per line
</p>
<textarea id="args"></textarea>
<h2>
Output
</h2>
<input id="go" type="button" value="Generate code" />
<textarea id="output"></textarea>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$(function(){
$("#go").click(function(){
var output = ""
var template = $("#template").val()
var args = $("#args").val()
// collect the args
var argLines = args.split("\n")
for (var line in argLines) {
var argLine = argLines[line];
var thisTemp = template
// get individual args
var args = argLine.split(",")
for (var argI in args) {
var argText = args[argI];
var argPlaceholder = "{" + argI + "}";
while (thisTemp.indexOf(argPlaceholder) > -1) {
thisTemp = thisTemp.replace(argPlaceholder, argText);
}
}
output += thisTemp
}
$("#output").val(output);
});
});
</script>
</body>
</html>
+286
View File
@@ -0,0 +1,286 @@
/*
{4} ({1} and []{1})
--------------------------------------------------
*/
// {4} gets the value as a {1}, returns the optionalDefault
// value or a system default object if the value is the wrong type.
func (v *Value) {4}(optionalDefault ...{1}) {1} {
if s, ok := v.data.({1}); ok {
return s
}
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return {3}
}
// Must{4} gets the value as a {1}.
//
// Panics if the object is not a {1}.
func (v *Value) Must{4}() {1} {
return v.data.({1})
}
// {4}Slice gets the value as a []{1}, returns the optionalDefault
// value or nil if the value is not a []{1}.
func (v *Value) {4}Slice(optionalDefault ...[]{1}) []{1} {
if s, ok := v.data.([]{1}); ok {
return s
}
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return nil
}
// Must{4}Slice gets the value as a []{1}.
//
// Panics if the object is not a []{1}.
func (v *Value) Must{4}Slice() []{1} {
return v.data.([]{1})
}
// Is{4} gets whether the object contained is a {1} or not.
func (v *Value) Is{4}() bool {
_, ok := v.data.({1})
return ok
}
// Is{4}Slice gets whether the object contained is a []{1} or not.
func (v *Value) Is{4}Slice() bool {
_, ok := v.data.([]{1})
return ok
}
// Each{4} calls the specified callback for each object
// in the []{1}.
//
// Panics if the object is the wrong type.
func (v *Value) Each{4}(callback func(int, {1}) bool) *Value {
for index, val := range v.Must{4}Slice() {
carryon := callback(index, val)
if carryon == false {
break
}
}
return v
}
// Where{4} uses the specified decider function to select items
// from the []{1}. The object contained in the result will contain
// only the selected items.
func (v *Value) Where{4}(decider func(int, {1}) bool) *Value {
var selected []{1}
v.Each{4}(func(index int, val {1}) bool {
shouldSelect := decider(index, val)
if shouldSelect == false {
selected = append(selected, val)
}
return true
})
return &Value{data:selected}
}
// Group{4} uses the specified grouper function to group the items
// keyed by the return of the grouper. The object contained in the
// result will contain a map[string][]{1}.
func (v *Value) Group{4}(grouper func(int, {1}) string) *Value {
groups := make(map[string][]{1})
v.Each{4}(func(index int, val {1}) bool {
group := grouper(index, val)
if _, ok := groups[group]; !ok {
groups[group] = make([]{1}, 0)
}
groups[group] = append(groups[group], val)
return true
})
return &Value{data:groups}
}
// Replace{4} uses the specified function to replace each {1}s
// by iterating each item. The data in the returned result will be a
// []{1} containing the replaced items.
func (v *Value) Replace{4}(replacer func(int, {1}) {1}) *Value {
arr := v.Must{4}Slice()
replaced := make([]{1}, len(arr))
v.Each{4}(func(index int, val {1}) bool {
replaced[index] = replacer(index, val)
return true
})
return &Value{data:replaced}
}
// Collect{4} uses the specified collector function to collect a value
// for each of the {1}s in the slice. The data returned will be a
// []interface{}.
func (v *Value) Collect{4}(collector func(int, {1}) interface{}) *Value {
arr := v.Must{4}Slice()
collected := make([]interface{}, len(arr))
v.Each{4}(func(index int, val {1}) bool {
collected[index] = collector(index, val)
return true
})
return &Value{data:collected}
}
// ************************************************************
// TESTS
// ************************************************************
func Test{4}(t *testing.T) {
val := {1}( {2} )
m := map[string]interface{}{"value": val, "nothing": nil}
assert.Equal(t, val, New(m).Get("value").{4}())
assert.Equal(t, val, New(m).Get("value").Must{4}())
assert.Equal(t, {1}({3}), New(m).Get("nothing").{4}())
assert.Equal(t, val, New(m).Get("nothing").{4}({2}))
assert.Panics(t, func() {
New(m).Get("age").Must{4}()
})
}
func Test{4}Slice(t *testing.T) {
val := {1}( {2} )
m := map[string]interface{}{"value": []{1}{ val }, "nothing": nil}
assert.Equal(t, val, New(m).Get("value").{4}Slice()[0])
assert.Equal(t, val, New(m).Get("value").Must{4}Slice()[0])
assert.Equal(t, []{1}(nil), New(m).Get("nothing").{4}Slice())
assert.Equal(t, val, New(m).Get("nothing").{4}Slice( []{1}{ {1}({2}) } )[0])
assert.Panics(t, func() {
New(m).Get("nothing").Must{4}Slice()
})
}
func TestIs{4}(t *testing.T) {
var v *Value
v = &Value{data: {1}({2})}
assert.True(t, v.Is{4}())
v = &Value{data: []{1}{ {1}({2}) }}
assert.True(t, v.Is{4}Slice())
}
func TestEach{4}(t *testing.T) {
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
count := 0
replacedVals := make([]{1}, 0)
assert.Equal(t, v, v.Each{4}(func(i int, val {1}) bool {
count++
replacedVals = append(replacedVals, val)
// abort early
if i == 2 {
return false
}
return true
}))
assert.Equal(t, count, 3)
assert.Equal(t, replacedVals[0], v.Must{4}Slice()[0])
assert.Equal(t, replacedVals[1], v.Must{4}Slice()[1])
assert.Equal(t, replacedVals[2], v.Must{4}Slice()[2])
}
func TestWhere{4}(t *testing.T) {
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
selected := v.Where{4}(func(i int, val {1}) bool {
return i%2==0
}).Must{4}Slice()
assert.Equal(t, 3, len(selected))
}
func TestGroup{4}(t *testing.T) {
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
grouped := v.Group{4}(func(i int, val {1}) string {
return fmt.Sprintf("%v", i%2==0)
}).data.(map[string][]{1})
assert.Equal(t, 2, len(grouped))
assert.Equal(t, 3, len(grouped["true"]))
assert.Equal(t, 3, len(grouped["false"]))
}
func TestReplace{4}(t *testing.T) {
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
rawArr := v.Must{4}Slice()
replaced := v.Replace{4}(func(index int, val {1}) {1} {
if index < len(rawArr)-1 {
return rawArr[index+1]
}
return rawArr[0]
})
replacedArr := replaced.Must{4}Slice()
if assert.Equal(t, 6, len(replacedArr)) {
assert.Equal(t, replacedArr[0], rawArr[1])
assert.Equal(t, replacedArr[1], rawArr[2])
assert.Equal(t, replacedArr[2], rawArr[3])
assert.Equal(t, replacedArr[3], rawArr[4])
assert.Equal(t, replacedArr[4], rawArr[5])
assert.Equal(t, replacedArr[5], rawArr[0])
}
}
func TestCollect{4}(t *testing.T) {
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
collected := v.Collect{4}(func(index int, val {1}) interface{} {
return index
})
collectedArr := collected.MustInterSlice()
if assert.Equal(t, 6, len(collectedArr)) {
assert.Equal(t, collectedArr[0], 0)
assert.Equal(t, collectedArr[1], 1)
assert.Equal(t, collectedArr[2], 2)
assert.Equal(t, collectedArr[3], 3)
assert.Equal(t, collectedArr[4], 4)
assert.Equal(t, collectedArr[5], 5)
}
}
+20
View File
@@ -0,0 +1,20 @@
Interface,interface{},"something",nil,Inter
Map,map[string]interface{},map[string]interface{}{"name":"Tyler"},nil,MSI
ObjxMap,(Map),New(1),New(nil),ObjxMap
Bool,bool,true,false,Bool
String,string,"hello","",Str
Int,int,1,0,Int
Int8,int8,1,0,Int8
Int16,int16,1,0,Int16
Int32,int32,1,0,Int32
Int64,int64,1,0,Int64
Uint,uint,1,0,Uint
Uint8,uint8,1,0,Uint8
Uint16,uint16,1,0,Uint16
Uint32,uint32,1,0,Uint32
Uint64,uint64,1,0,Uint64
Uintptr,uintptr,1,0,Uintptr
Float32,float32,1,0,Float32
Float64,float64,1,0,Float64
Complex64,complex64,1,0,Complex64
Complex128,complex128,1,0,Complex128
+13
View File
@@ -0,0 +1,13 @@
package objx
const (
// PathSeparator is the character used to separate the elements
// of the keypath.
//
// For example, `location.address.city`
PathSeparator string = "."
// SignatureSeparator is the character that is used to
// separate the Base64 string from the security signature.
SignatureSeparator = "_"
)

Some files were not shown because too many files have changed in this diff Show More