lg 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Guardfile +20 -0
- data/README.md +117 -0
- data/Rakefile +1 -0
- data/bin/lg +13 -0
- data/lib/gist_store/cacert.pem +116 -0
- data/lib/gist_store/gist.rb +255 -0
- data/lib/gist_store/gist_store.rb +62 -0
- data/lib/gist_store/net_http_ext.rb +56 -0
- data/lib/logbook.rb +14 -0
- data/lib/logbook/book.rb +79 -0
- data/lib/logbook/cli.rb +127 -0
- data/lib/logbook/version.rb +3 -0
- data/logbook.gemspec +29 -0
- data/spec/gist_store/gist_store_spec.rb +86 -0
- data/spec/logbook/book_spec.rb +82 -0
- data/spec/logbook/cli_spec.rb +134 -0
- data/spec/spec_helper.rb +58 -0
- metadata +131 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'minitest' do
|
5
|
+
|
6
|
+
# with Minitest::Spec
|
7
|
+
watch(%r|^spec/(.*)_spec\.rb|)
|
8
|
+
watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
9
|
+
watch(%r|^spec/spec_helper\.rb|) { "spec" }
|
10
|
+
|
11
|
+
# Rails 3.2
|
12
|
+
# watch(%r|^app/controllers/(.*)\.rb|) { |m| "test/controllers/#{m[1]}_test.rb" }
|
13
|
+
# watch(%r|^app/helpers/(.*)\.rb|) { |m| "test/helpers/#{m[1]}_test.rb" }
|
14
|
+
# watch(%r|^app/models/(.*)\.rb|) { |m| "test/unit/#{m[1]}_test.rb" }
|
15
|
+
|
16
|
+
# Rails
|
17
|
+
# watch(%r|^app/controllers/(.*)\.rb|) { |m| "test/functional/#{m[1]}_test.rb" }
|
18
|
+
# watch(%r|^app/helpers/(.*)\.rb|) { |m| "test/helpers/#{m[1]}_test.rb" }
|
19
|
+
# watch(%r|^app/models/(.*)\.rb|) { |m| "test/unit/#{m[1]}_test.rb" }
|
20
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# Logbook
|
2
|
+
|
3
|
+
Logbook allows you to record memories easily from your command line into
|
4
|
+
virtual book(s). Books are simply private Github Gists (backend is
|
5
|
+
replaceable).
|
6
|
+
|
7
|
+
|
8
|
+
It is heavily inspired from its pythonish friend, http://maebert.github.com/jrnl.
|
9
|
+
|
10
|
+
I built it because I love Ruby, it was easy enough, and I really loved
|
11
|
+
the idea of storing as Gists as opposed to plain files.
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
# Usage
|
16
|
+
|
17
|
+
For brevity's sake, the Logbook gem name and executable is `lg`.
|
18
|
+
|
19
|
+
$ gem install lg
|
20
|
+
$ lg
|
21
|
+
|
22
|
+
|
23
|
+
If you want private Gists attached to your user (you most probably
|
24
|
+
want that), make sure to set your Github credentials as environment
|
25
|
+
variables, example:
|
26
|
+
|
27
|
+
$ export GITHUB_USER=youruser
|
28
|
+
$ export GITHUB_PASSWORD=yourpw
|
29
|
+
|
30
|
+
Now we need to make a first `book` and start `add`ing into it.
|
31
|
+
|
32
|
+
## Setting up a book
|
33
|
+
|
34
|
+
Create a new book with the `lg book` command. You can give it a
|
35
|
+
cover, in this case `The Wizzard of Oz`.
|
36
|
+
|
37
|
+
$ lg book The Wizzard of Oz
|
38
|
+
|
39
|
+
|
40
|
+
## Adding lgries
|
41
|
+
|
42
|
+
Simply say 'lg add' and your memory in a short sentence.
|
43
|
+
|
44
|
+
$ lg add just wrote the logbook gem README
|
45
|
+
|
46
|
+
You might find it convenient to specify when a thing happend explicitly,
|
47
|
+
just make sure to specify a natural date such as `yesterday` separated
|
48
|
+
by a colon `:`. Translation done with the `chronic` gem.
|
49
|
+
|
50
|
+
$ lg add yesterday: wrote the logbook gem README
|
51
|
+
|
52
|
+
|
53
|
+
## More
|
54
|
+
|
55
|
+
You can safely skip this if that's all what you're looking for.
|
56
|
+
|
57
|
+
## Switching books
|
58
|
+
|
59
|
+
Switch between books, when you know what you want, you can explicitly
|
60
|
+
specify the ID.
|
61
|
+
|
62
|
+
$ lg book book-id
|
63
|
+
|
64
|
+
Or pick from a menu, leaving arguments blank:
|
65
|
+
|
66
|
+
$ lg book
|
67
|
+
1 The Wizzard of Oz deadbeef0aef
|
68
|
+
...
|
69
|
+
Pick one: 1
|
70
|
+
|
71
|
+
|
72
|
+
## Listing lgries
|
73
|
+
|
74
|
+
Say `lg all` when you want to see everything you've recorded.
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
# Philosophy
|
80
|
+
|
81
|
+
Command line is awesome. Its fast, and you feel it when you're less
|
82
|
+
dependent on your mouse for your development work (e.g. VIM).
|
83
|
+
|
84
|
+
You should just Alt/Command-Tab, write a line and go back working.
|
85
|
+
|
86
|
+
You should be expected to remember at most one commands (pitfall of success) to do actual work. Seriously, [focus](http://ezliu.com/focus/).
|
87
|
+
|
88
|
+
|
89
|
+
## There's no search like in jrnl
|
90
|
+
|
91
|
+
Feature slim. Use gist search for that. True, its limited, but as of now, I believe
|
92
|
+
Github are working on improving that.
|
93
|
+
|
94
|
+
In actuallity, `jrnl`'s search loads all of your entries to memory and
|
95
|
+
performs search on an in-memory structure.
|
96
|
+
If the need arises, it should be dead easy to
|
97
|
+
make *that* kind of search in `logbook`.
|
98
|
+
|
99
|
+
## There's no delete/modify
|
100
|
+
|
101
|
+
Again, feature slim. If you were using a real logbook, you'd
|
102
|
+
just cross the bad entry. It will still be there.
|
103
|
+
If you must, you can always use the gist interface for that.
|
104
|
+
|
105
|
+
## There's no analytics, let me reap added value from my work!
|
106
|
+
|
107
|
+
Actually, a gist entry is a Git repository.
|
108
|
+
The modeling on-top-of a
|
109
|
+
Gist was done intentionally. Clone your book and
|
110
|
+
treat it like a Git repo.
|
111
|
+
|
112
|
+
From there, you can script against git and/or run countless analysis tools on your repository.
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/lg
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
Certificate chain
|
2
|
+
0 s:/O=*.github.com/OU=Domain Control Validated/CN=*.github.com
|
3
|
+
i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
|
4
|
+
-----BEGIN CERTIFICATE-----
|
5
|
+
MIIFVTCCBD2gAwIBAgIHBGX+dPs18DANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
|
6
|
+
BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
|
7
|
+
BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm
|
8
|
+
aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5
|
9
|
+
IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky
|
10
|
+
ODcwHhcNMDkxMjExMDUwMjM2WhcNMTQxMjExMDUwMjM2WjBRMRUwEwYDVQQKEwwq
|
11
|
+
LmdpdGh1Yi5jb20xITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEV
|
12
|
+
MBMGA1UEAxMMKi5naXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
13
|
+
CgKCAQEA7dOJw11wcgnzM08acnTZtlqVULtoYZ/3+x8Z4doEMa8VfBp/+XOvHeVD
|
14
|
+
K1YJAEVpSujEW9/Cd1JRGVvRK9k5ZTagMhkcQXP7MrI9n5jsglsLN2Q5LLcQg3LN
|
15
|
+
8OokS/rZlC7DhRU5qTr2iNr0J4mmlU+EojdOfCV4OsmDbQIXlXh9R6hVg+4TyBka
|
16
|
+
szzxX/47AuGF+xFmqwldn0xD8MckXilyKM7UdWhPJHIprjko/N+NT02Dc3QMbxGb
|
17
|
+
p91i3v/i6xfm/wy/wC0xO9ZZovLdh0pIe20zERRNNJ8yOPbIGZ3xtj3FRu9RC4rG
|
18
|
+
M+1IYcQdFxu9fLZn6TnPpVKACvTqzQIDAQABo4IBtjCCAbIwDwYDVR0TAQH/BAUw
|
19
|
+
AwEBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQD
|
20
|
+
AgWgMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Rz
|
21
|
+
MS0xMS5jcmwwUwYDVR0gBEwwSjBIBgtghkgBhv1tAQcXATA5MDcGCCsGAQUFBwIB
|
22
|
+
FitodHRwOi8vY2VydGlmaWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMIGA
|
23
|
+
BggrBgEFBQcBAQR0MHIwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmdvZGFkZHku
|
24
|
+
Y29tLzBKBggrBgEFBQcwAoY+aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv
|
25
|
+
bS9yZXBvc2l0b3J5L2dkX2ludGVybWVkaWF0ZS5jcnQwHwYDVR0jBBgwFoAU/axh
|
26
|
+
MpNsRdbi7oVfmrrndplozOcwIwYDVR0RBBwwGoIMKi5naXRodWIuY29tggpnaXRo
|
27
|
+
dWIuY29tMB0GA1UdDgQWBBSH0Y8ZbuSHb1OMd5EHUN+jv1VHIDANBgkqhkiG9w0B
|
28
|
+
AQUFAAOCAQEAwIe/Bbuk1/r38aqb5wlXjoW6tAmLpzLRkKorDOcDUJLtN6a9XqAk
|
29
|
+
cgMai7NCI1YV+A4IjEENj53mV2xWLpniqLDHI5y2NbQuL2deu1jQSSNz7xE/nZCk
|
30
|
+
WGt8OEtm6YI2bUsq5EXy078avRbigBko1bqtFuG0s5+nFrKCjhQVIk+GX7cwiyr4
|
31
|
+
XJ49FxETvePrxNYr7x7n/Jju59KXTw3juPET+bAwNlRXmScjrMylMNUMr3sFcyLz
|
32
|
+
DciaVnnextu6+L0w1+5KNVbMKndRwgg/cRldBL4AgmtouTC3mlDGGG3U6eV75cdH
|
33
|
+
D03DXDfrYYjxmWjTRdO2GdbYnt1ToEgxyA==
|
34
|
+
-----END CERTIFICATE-----
|
35
|
+
1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
|
36
|
+
i:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
|
37
|
+
-----BEGIN CERTIFICATE-----
|
38
|
+
MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx
|
39
|
+
ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
|
40
|
+
RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw
|
41
|
+
MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH
|
42
|
+
QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j
|
43
|
+
b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j
|
44
|
+
b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj
|
45
|
+
YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN
|
46
|
+
AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H
|
47
|
+
KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm
|
48
|
+
VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR
|
49
|
+
SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT
|
50
|
+
cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ
|
51
|
+
6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu
|
52
|
+
MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS
|
53
|
+
kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB
|
54
|
+
BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f
|
55
|
+
BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv
|
56
|
+
c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH
|
57
|
+
AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO
|
58
|
+
BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG
|
59
|
+
OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU
|
60
|
+
A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o
|
61
|
+
0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX
|
62
|
+
RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH
|
63
|
+
qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV
|
64
|
+
U+4=
|
65
|
+
-----END CERTIFICATE-----
|
66
|
+
2 s:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
|
67
|
+
i:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com
|
68
|
+
-----BEGIN CERTIFICATE-----
|
69
|
+
MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh
|
70
|
+
bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
|
71
|
+
Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g
|
72
|
+
QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe
|
73
|
+
BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX
|
74
|
+
DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE
|
75
|
+
YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0
|
76
|
+
aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC
|
77
|
+
ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
|
78
|
+
2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q
|
79
|
+
N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO
|
80
|
+
r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN
|
81
|
+
f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH
|
82
|
+
U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU
|
83
|
+
TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb
|
84
|
+
VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg
|
85
|
+
SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv
|
86
|
+
biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg
|
87
|
+
MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw
|
88
|
+
AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv
|
89
|
+
ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu
|
90
|
+
Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd
|
91
|
+
IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv
|
92
|
+
bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1
|
93
|
+
QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O
|
94
|
+
WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf
|
95
|
+
SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==
|
96
|
+
-----END CERTIFICATE-----
|
97
|
+
3 s:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com
|
98
|
+
i:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com
|
99
|
+
-----BEGIN CERTIFICATE-----
|
100
|
+
MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
|
101
|
+
IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
|
102
|
+
BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
|
103
|
+
aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
|
104
|
+
9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
|
105
|
+
NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
|
106
|
+
azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
|
107
|
+
YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
|
108
|
+
Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
|
109
|
+
cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
|
110
|
+
dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
|
111
|
+
WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
|
112
|
+
v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
|
113
|
+
UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
|
114
|
+
IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
|
115
|
+
W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
|
116
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,255 @@
|
|
1
|
+
require 'gist_store/net_http_ext'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'net/https'
|
4
|
+
require 'optparse'
|
5
|
+
require 'json'
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
# You can use this class from other scripts with the greatest of
|
11
|
+
# ease.
|
12
|
+
#
|
13
|
+
# >> Gist.read(gist_id)
|
14
|
+
# Returns the body of gist_id as a string.
|
15
|
+
#
|
16
|
+
# >> Gist.write(content)
|
17
|
+
# Creates a gist from the string `content`. Returns the URL of the
|
18
|
+
# new gist.
|
19
|
+
#
|
20
|
+
# >> Gist.copy(string)
|
21
|
+
# Copies string to the clipboard.
|
22
|
+
#
|
23
|
+
# >> Gist.browse(url)
|
24
|
+
# Opens URL in your default browser.
|
25
|
+
module Gist
|
26
|
+
extend self
|
27
|
+
|
28
|
+
GIST_URL = 'https://api.github.com/gists/%s'
|
29
|
+
CREATE_URL = 'https://api.github.com/gists'
|
30
|
+
|
31
|
+
if ENV['HTTPS_PROXY']
|
32
|
+
PROXY = URI(ENV['HTTPS_PROXY'])
|
33
|
+
elsif ENV['HTTP_PROXY']
|
34
|
+
PROXY = URI(ENV['HTTP_PROXY'])
|
35
|
+
else
|
36
|
+
PROXY = nil
|
37
|
+
end
|
38
|
+
PROXY_HOST = PROXY ? PROXY.host : nil
|
39
|
+
PROXY_PORT = PROXY ? PROXY.port : nil
|
40
|
+
|
41
|
+
|
42
|
+
# Create a gist on gist.github.com
|
43
|
+
def write(files, private_gist = false, description = nil)
|
44
|
+
url = URI.parse(CREATE_URL)
|
45
|
+
|
46
|
+
if PROXY_HOST
|
47
|
+
proxy = Net::HTTP::Proxy(PROXY_HOST, PROXY_PORT)
|
48
|
+
http = proxy.new(url.host, url.port)
|
49
|
+
else
|
50
|
+
http = Net::HTTP.new(url.host, url.port)
|
51
|
+
end
|
52
|
+
|
53
|
+
http.use_ssl = true
|
54
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
55
|
+
http.ca_file = ca_cert
|
56
|
+
|
57
|
+
req = Net::HTTP::Post.new(url.path)
|
58
|
+
req.body = JSON.generate(data(files, private_gist, description))
|
59
|
+
|
60
|
+
user, password = auth()
|
61
|
+
if user && password
|
62
|
+
req.basic_auth(user, password)
|
63
|
+
end
|
64
|
+
|
65
|
+
response = http.start{|h| h.request(req) }
|
66
|
+
case response
|
67
|
+
when Net::HTTPCreated
|
68
|
+
JSON.parse(response.body)['html_url']
|
69
|
+
else
|
70
|
+
raise "Creating gist failed: #{response.code} #{response.message}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Create a gist on gist.github.com
|
75
|
+
def update(id, files)
|
76
|
+
url = URI.parse(CREATE_URL)
|
77
|
+
|
78
|
+
if PROXY_HOST
|
79
|
+
proxy = Net::HTTP::Proxy(PROXY_HOST, PROXY_PORT)
|
80
|
+
http = proxy.new(url.host, url.port)
|
81
|
+
else
|
82
|
+
http = Net::HTTP.new(url.host, url.port)
|
83
|
+
end
|
84
|
+
|
85
|
+
http.use_ssl = true
|
86
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
87
|
+
http.ca_file = ca_cert
|
88
|
+
|
89
|
+
req = Net::HTTP::Patch.new(GIST_URL % id)
|
90
|
+
req.body = JSON.generate(data(files, nil, nil))
|
91
|
+
|
92
|
+
user, password = auth()
|
93
|
+
if user && password
|
94
|
+
req.basic_auth(user, password)
|
95
|
+
end
|
96
|
+
|
97
|
+
response = http.start{|h| h.request(req) }
|
98
|
+
case response
|
99
|
+
when Net::HTTPOK
|
100
|
+
JSON.parse(response.body)['html_url']
|
101
|
+
else
|
102
|
+
raise "Updating gist failed: #{response.code} #{response.message}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
# Create a gist on gist.github.com
|
109
|
+
def delete(id)
|
110
|
+
url = URI.parse(CREATE_URL)
|
111
|
+
|
112
|
+
if PROXY_HOST
|
113
|
+
proxy = Net::HTTP::Proxy(PROXY_HOST, PROXY_PORT)
|
114
|
+
http = proxy.new(url.host, url.port)
|
115
|
+
else
|
116
|
+
http = Net::HTTP.new(url.host, url.port)
|
117
|
+
end
|
118
|
+
|
119
|
+
http.use_ssl = true
|
120
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
121
|
+
http.ca_file = ca_cert
|
122
|
+
|
123
|
+
req = Net::HTTP::Delete.new(GIST_URL % id)
|
124
|
+
|
125
|
+
user, password = auth()
|
126
|
+
if user && password
|
127
|
+
req.basic_auth(user, password)
|
128
|
+
end
|
129
|
+
|
130
|
+
response = http.start{|h| h.request(req) }
|
131
|
+
case response
|
132
|
+
when Net::HTTPNoContent
|
133
|
+
true
|
134
|
+
else
|
135
|
+
raise "Creating gist failed: #{response.code} #{response.message}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Given a gist id, returns its content.
|
140
|
+
def read(gist_id)
|
141
|
+
data = read_raw(gist_id)
|
142
|
+
data["files"].map{|name, content| content['content'] }.join("\n\n")
|
143
|
+
end
|
144
|
+
|
145
|
+
def read_raw(gist_id)
|
146
|
+
data = JSON.parse(open(GIST_URL % gist_id).read)
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
private
|
151
|
+
# Give an array of file information and private boolean, returns
|
152
|
+
# an appropriate payload for POSTing to gist.github.com
|
153
|
+
def data(files, private_gist, description)
|
154
|
+
i = 0
|
155
|
+
file_data = {}
|
156
|
+
files.each do |file|
|
157
|
+
i = i + 1
|
158
|
+
filename = file[:filename] ? file[:filename] : "gistfile#{i}"
|
159
|
+
file_data[filename] = {:content => file[:input]}
|
160
|
+
end
|
161
|
+
|
162
|
+
data = {"files" => file_data}
|
163
|
+
data.merge!({ 'description' => description }) unless description.nil?
|
164
|
+
data.merge!({ 'public' => !private_gist }) unless private_gist.nil?
|
165
|
+
data
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns a basic auth string of the user's GitHub credentials if set.
|
169
|
+
# http://github.com/guides/local-github-config
|
170
|
+
#
|
171
|
+
# Returns an Array of Strings if auth is found: [user, password]
|
172
|
+
# Returns nil if no auth is found.
|
173
|
+
def auth
|
174
|
+
user = config("github.user")
|
175
|
+
password = config("github.password")
|
176
|
+
|
177
|
+
token = config("github.token")
|
178
|
+
if password.to_s.empty? && !token.to_s.empty?
|
179
|
+
raise "Please set GITHUB_PASSWORD or github.password instead of using a token."
|
180
|
+
end
|
181
|
+
|
182
|
+
if user.to_s.empty? || password.to_s.empty?
|
183
|
+
nil
|
184
|
+
else
|
185
|
+
[ user, password ]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns default values based on settings in your gitconfig. See
|
190
|
+
# git-config(1) for more information.
|
191
|
+
#
|
192
|
+
# Settings applicable to gist.rb are:
|
193
|
+
#
|
194
|
+
# gist.private - boolean
|
195
|
+
# gist.extension - string
|
196
|
+
def defaults
|
197
|
+
extension = config("gist.extension")
|
198
|
+
|
199
|
+
return {
|
200
|
+
"private" => config("gist.private"),
|
201
|
+
"browse" => config("gist.browse"),
|
202
|
+
"extension" => extension
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
# Reads a config value using:
|
207
|
+
# => Environment: GITHUB_PASSWORD, GITHUB_USER
|
208
|
+
# like vim gist plugin
|
209
|
+
# => git-config(1)
|
210
|
+
#
|
211
|
+
# return something useful or nil
|
212
|
+
def config(key)
|
213
|
+
env_key = ENV[key.upcase.gsub(/\./, '_')]
|
214
|
+
return env_key if env_key and not env_key.strip.empty?
|
215
|
+
|
216
|
+
str_to_bool `git config --global #{key}`.strip
|
217
|
+
end
|
218
|
+
|
219
|
+
# Parses a value that might appear in a .gitconfig file into
|
220
|
+
# something useful in a Ruby script.
|
221
|
+
def str_to_bool(str)
|
222
|
+
if str.size > 0 and str[0].chr == '!'
|
223
|
+
command = str[1, str.length]
|
224
|
+
value = `#{command}`
|
225
|
+
else
|
226
|
+
value = str
|
227
|
+
end
|
228
|
+
|
229
|
+
case value.downcase.strip
|
230
|
+
when "false", "0", "nil", "", "no", "off"
|
231
|
+
nil
|
232
|
+
when "true", "1", "yes", "on"
|
233
|
+
true
|
234
|
+
else
|
235
|
+
value
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def ca_cert
|
240
|
+
cert_file = [
|
241
|
+
File.expand_path("../cacert.pem", __FILE__),
|
242
|
+
"/tmp/gist_cacert.pem"
|
243
|
+
].find{|l| File.exist?(l) }
|
244
|
+
|
245
|
+
if cert_file
|
246
|
+
cert_file
|
247
|
+
else
|
248
|
+
File.open("/tmp/gist_cacert.pem", "w") do |f|
|
249
|
+
f.write(DATA.read.split("__CACERT__").last)
|
250
|
+
end
|
251
|
+
"/tmp/gist_cacert.pem"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|