tinyci 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +97 -0
- data/Guardfile +7 -0
- data/LICENSE +21 -0
- data/README.md +211 -0
- data/Rakefile +1 -0
- data/bin/tinyci +10 -0
- data/lib/pidfile.rb +150 -0
- data/lib/tinyci/builders/rkt_builder.rb +31 -0
- data/lib/tinyci/builders/script_builder.rb +18 -0
- data/lib/tinyci/builders/test_builder.rb +11 -0
- data/lib/tinyci/cli.rb +104 -0
- data/lib/tinyci/config.rb +55 -0
- data/lib/tinyci/executor.rb +21 -0
- data/lib/tinyci/git_utils.rb +68 -0
- data/lib/tinyci/installer.rb +55 -0
- data/lib/tinyci/logging.rb +16 -0
- data/lib/tinyci/logo.txt +6 -0
- data/lib/tinyci/multi_logger.rb +49 -0
- data/lib/tinyci/runner.rb +154 -0
- data/lib/tinyci/scheduler.rb +105 -0
- data/lib/tinyci/subprocesses.rb +111 -0
- data/lib/tinyci/symbolize.rb +22 -0
- data/lib/tinyci/testers/rkt_tester.rb +40 -0
- data/lib/tinyci/testers/script_tester.rb +18 -0
- data/lib/tinyci/testers/test_tester.rb +11 -0
- data/lib/tinyci/version.rb +3 -0
- data/tinyci.gemspec +44 -0
- metadata +179 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7a0de56d2686e1af8a2960bdfb0b8ac3eba240ed
|
4
|
+
data.tar.gz: f1529cf28f2e9a10fb36bda7085cf465935ee59a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 42639f2ca97b82a9ad3fc43cc6e35cfc8052659f6aaef73ebaabed6342bb12f66b64060f3856c19d785af15c8ba7ac0fe93365943ff17fc65b42b849e32c305e
|
7
|
+
data.tar.gz: 9406072d6fae373d7cbfb933e4c8856e57d0f41d93a3e753b9bb773e85a708a9405ba9029c889962e02d275b99645aac7b0b7cb4c41486dd72fefccc1d622400
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.2
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup=markdown
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
tinyci (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
awesome_print (1.8.0)
|
10
|
+
barrier (1.0.2)
|
11
|
+
byebug (9.1.0)
|
12
|
+
coderay (1.1.2)
|
13
|
+
diff-lcs (1.3)
|
14
|
+
ffi (1.9.18)
|
15
|
+
formatador (0.2.5)
|
16
|
+
fuubar (2.2.0)
|
17
|
+
rspec-core (~> 3.0)
|
18
|
+
ruby-progressbar (~> 1.4)
|
19
|
+
guard (2.14.1)
|
20
|
+
formatador (>= 0.2.4)
|
21
|
+
listen (>= 2.7, < 4.0)
|
22
|
+
lumberjack (~> 1.0)
|
23
|
+
nenv (~> 0.1)
|
24
|
+
notiffany (~> 0.0)
|
25
|
+
pry (>= 0.9.12)
|
26
|
+
shellany (~> 0.0)
|
27
|
+
thor (>= 0.18.1)
|
28
|
+
guard-compat (1.2.1)
|
29
|
+
guard-rspec (4.7.3)
|
30
|
+
guard (~> 2.1)
|
31
|
+
guard-compat (~> 1.1)
|
32
|
+
rspec (>= 2.99.0, < 4.0)
|
33
|
+
listen (3.1.5)
|
34
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
35
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
36
|
+
ruby_dep (~> 1.2)
|
37
|
+
lumberjack (1.0.12)
|
38
|
+
method_source (0.9.0)
|
39
|
+
nenv (0.3.0)
|
40
|
+
notiffany (0.1.1)
|
41
|
+
nenv (~> 0.1)
|
42
|
+
shellany (~> 0.0)
|
43
|
+
pry (0.11.1)
|
44
|
+
coderay (~> 1.1.0)
|
45
|
+
method_source (~> 0.9.0)
|
46
|
+
pry-byebug (3.5.0)
|
47
|
+
byebug (~> 9.1)
|
48
|
+
pry (~> 0.10)
|
49
|
+
rake (12.1.0)
|
50
|
+
rb-fsevent (0.10.2)
|
51
|
+
rb-inotify (0.9.10)
|
52
|
+
ffi (>= 0.5.0, < 2)
|
53
|
+
redcarpet (3.4.0)
|
54
|
+
rspec (3.6.0)
|
55
|
+
rspec-core (~> 3.6.0)
|
56
|
+
rspec-expectations (~> 3.6.0)
|
57
|
+
rspec-mocks (~> 3.6.0)
|
58
|
+
rspec-core (3.6.0)
|
59
|
+
rspec-support (~> 3.6.0)
|
60
|
+
rspec-expectations (3.6.0)
|
61
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
62
|
+
rspec-support (~> 3.6.0)
|
63
|
+
rspec-mocks (3.6.0)
|
64
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
65
|
+
rspec-support (~> 3.6.0)
|
66
|
+
rspec-nc (0.3.0)
|
67
|
+
rspec (>= 3)
|
68
|
+
terminal-notifier (>= 1.4)
|
69
|
+
rspec-support (3.6.0)
|
70
|
+
ruby-progressbar (1.8.1)
|
71
|
+
ruby_dep (1.5.0)
|
72
|
+
shellany (0.0.1)
|
73
|
+
terminal-notifier (1.7.1)
|
74
|
+
thor (0.20.0)
|
75
|
+
yard (0.9.12)
|
76
|
+
|
77
|
+
PLATFORMS
|
78
|
+
ruby
|
79
|
+
|
80
|
+
DEPENDENCIES
|
81
|
+
awesome_print
|
82
|
+
barrier
|
83
|
+
bundler (~> 1.14)
|
84
|
+
fuubar
|
85
|
+
guard-rspec
|
86
|
+
pry
|
87
|
+
pry-byebug
|
88
|
+
rake
|
89
|
+
redcarpet
|
90
|
+
rspec
|
91
|
+
rspec-nc
|
92
|
+
terminal-notifier (= 1.7.1)
|
93
|
+
tinyci!
|
94
|
+
yard
|
95
|
+
|
96
|
+
BUNDLED WITH
|
97
|
+
1.16.0.pre.3
|
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2018 Jonathan Davies
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
_____ _ _____ _____
|
2
|
+
/__ (_)_ __ _ _ / ___/ /_ _/
|
3
|
+
| || | '_ \| | | |/ / / /
|
4
|
+
| || | | | | |_| / /___/\/ /_
|
5
|
+
|_||_|_| |_|\__, \____/\____/
|
6
|
+
|___/
|
7
|
+
|
8
|
+
TinyCI
|
9
|
+
======
|
10
|
+
|
11
|
+
A minimal Continuous Integration system, written in ruby, powered by git. MIT licensed.
|
12
|
+
|
13
|
+
### Motivation
|
14
|
+
|
15
|
+
Existing CI solutions like [Travis](https://travis-ci.org) and [Jenkins](https://jenkins.io) run as daemons requiring large amounts of RAM, typically in their own virtual machines. A more lightweight system was desired, for use with small scale personal projects.
|
16
|
+
|
17
|
+
### Architecture
|
18
|
+
|
19
|
+
#### Requirements
|
20
|
+
|
21
|
+
TinyCI is written in ruby 2. It is not known exactly how recent a version of git is required, however development and testing was carried out against 2.7.4, the version packaged for ubuntu 16.04.
|
22
|
+
|
23
|
+
It does not have a heavy dependency on ruby 2, mainly making use of convenient syntactic features. Porting to ruby 1.9 would be very simple.
|
24
|
+
|
25
|
+
#### Stages
|
26
|
+
|
27
|
+
TinyCI is executed via git `post-update` hooks. When a new commit is pushed, the following steps are executed:
|
28
|
+
|
29
|
+
1. Clean
|
30
|
+
The [export path](#Export_Path) is removed
|
31
|
+
2. Export
|
32
|
+
A clean copy of the commit is placed at the [export path](#Export_Path). Clean in this context means without any .git directory or similar.
|
33
|
+
3. Build
|
34
|
+
The project's build command is executed
|
35
|
+
4. Test
|
36
|
+
The project's test command is executed
|
37
|
+
|
38
|
+
Finally the result is stored in git using the [git-notes](https://git-scm.com/docs/git-notes) feature. This is how TinyCI determines which commits to run against.
|
39
|
+
|
40
|
+
#### Eligible Commits
|
41
|
+
|
42
|
+
When TinyCI is executed, it runs against all eligible commits, from oldest to newest. At the present time, all commits without any `tinyci-result` git-notes object attached are eligible. This means that the first time TinyCI executes, it will run against every commit in the repository's history.
|
43
|
+
|
44
|
+
While this is obviously suboptimal, note that if no configuration file is found, the exported copy of the commit is deleted and TinyCI moves on to the next commit, so this will not create a huge number of extraneous exports. It would be desirable to check for the presence of the config file before exporting the entire commit with a call to `git-cat-file`, see the [TODO section](#Limitations_TODO) below.
|
45
|
+
|
46
|
+
#### Executor Classes
|
47
|
+
|
48
|
+
Building and Testing are done by subclasses of {TinyCI::Executor}. An instance of each is created for every commit TinyCI runs against. This enables "pluggable backends" for TinyCI. At present there is only the `ScriptBuilder` and `ScriptTester`, which just run a command specified in the config file.
|
49
|
+
|
50
|
+
#### Export Path
|
51
|
+
|
52
|
+
The export path is the location where exported copies of commits are placed. Currently it is hardcoded as a directory called `builds` under the repo root, or under the the `.git` directory in the case of a non-bare repository.
|
53
|
+
|
54
|
+
#### Configuration
|
55
|
+
|
56
|
+
TinyCI is configured with a YAML file named `.tinyci.yml` in the root directory of the repo. There are two sections, one for the builder and one for the tester. Each has a `class` key which specifies the {TinyCI::Executor} subclass to be used, and a `config` key which contains specific configuration for that executor. This `config` object can contain anything, it is passed wholesale to the executor object. For an example, see below, or see the example project.
|
57
|
+
|
58
|
+
#### Execution Model
|
59
|
+
|
60
|
+
TinyCI uses a pidfile to guarantee only a single executing process at a time. This ensures that multiple team members committing to a repository concurrently, or rapid commits in succession by a single user do not result in multiple concurrent executions of the test suite.
|
61
|
+
|
62
|
+
Because TinyCI checks anew for eligible git objects to run against after each iteration of its main loop, and runs until no more are found, in the event of multiple commits being pushed concurrently, or further commits being pushed while an initial commit is still being built and tested, the first TinyCI instance will eventually execute against all commits.
|
63
|
+
|
64
|
+
It is of course possible that commits might be pushed consistently faster than they can be tested, resulting in a never-to-be-cleared backlog; if this is the case the a more substantial CI solution is probably advisable for your project.
|
65
|
+
|
66
|
+
If you look in the source code you will also find `RktBuilder` and `RktTester`, these were experimental attempts to integrate the Rkt container runtime. They are not recommended for use but are left for users to examine.
|
67
|
+
|
68
|
+
#### Logging/Output
|
69
|
+
|
70
|
+
TinyCI is executed in a `post-update` git hook. As such, the output is shown to the user as part of the local call to `git push`. Once the TinyCI hook is running, the local git process can be freely killed if the user does not wish to watch the output - this will not affect the remote execution of TinyCI.
|
71
|
+
|
72
|
+
As well as logging to stdout, the TinyCI process writes a `tinyci.log` file in each exported directory.
|
73
|
+
|
74
|
+
#### Limitations/TODO
|
75
|
+
|
76
|
+
* TinyCI currently has no support for running a script on success or failure of the test script. This feature would allow for notifications to be sent, eg. slack bots, email, etc. It would also enable TinyCI to act as part of an automated deployment system.
|
77
|
+
|
78
|
+
* As mentioned above, when TinyCI is executed against a commit without a configuration file, it exports the whole directory, finds the config file to be missing, then deletes the export. As such, when TinyCI installed against an existing project with many commits, this process will happen for every commit, wasting a lot of time and churning the disk.
|
79
|
+
Instead, it would be preferable to check for the config file before doing the export, with a call to `git-cat-file`. An additional way to handle this would be to prevent the processing of commits created prior to the installation of TinyCI, perhaps by marking them with git-notes at install time, or by checking the creation date of the hook file.
|
80
|
+
|
81
|
+
* Presently, if a user kills their local git process while TinyCI is running, it will continue to execute on the server. If they then push another commit, the original TinyCI process will go on to test the second commit as well, as expected. However, the output from the second git push will simply consist of an error message describing the behavior.
|
82
|
+
Instead, this second TinyCI execution should begin tailing the output of the first process, perhaps gaining direct access to it's stdout stream.
|
83
|
+
|
84
|
+
* It would be desirable to add a command to the TinyCI binary to SSH into the remote server and tail the the log output of a currently running TinyCI process, enabling functionality similar to that described in above, but without making a new commit.
|
85
|
+
|
86
|
+
* The exported copies of each build are left on the disk forever. This will obviously eat disk space. One could handle deleting/compressing them with a cronjob, however it would be desirable to integrate this functionality into TinyCI and to automate it.
|
87
|
+
|
88
|
+
* More configuration options should be added, eg. specification of the export path.
|
89
|
+
|
90
|
+
* In general, more local functionality for the TinyCI binary would be desirable, some way to retrieve the results of tests and query them from the local clone for example, or some way to show them in `git log` output.
|
91
|
+
|
92
|
+
### Usage
|
93
|
+
|
94
|
+
#### Instructions
|
95
|
+
|
96
|
+
First, add a configuration file to your project:
|
97
|
+
|
98
|
+
cat <<EOF > .tinyci.yml
|
99
|
+
builder:
|
100
|
+
class: ScriptBuilder
|
101
|
+
config:
|
102
|
+
command: build.sh
|
103
|
+
tester:
|
104
|
+
class: ScriptTester
|
105
|
+
config:
|
106
|
+
command: test.sh
|
107
|
+
EOF
|
108
|
+
|
109
|
+
This config assumes you have files called `build.sh` and `test.sh` in the root of your project that execute the appropriate commands.
|
110
|
+
|
111
|
+
TinyCI is distributed as a ruby gem. Install it like so:
|
112
|
+
|
113
|
+
gem install tinyci
|
114
|
+
|
115
|
+
The gem should be installed on the remote server where you want the tests to execute. On that server, install TinyCI into your repository with the install command:
|
116
|
+
|
117
|
+
tinyci install
|
118
|
+
|
119
|
+
Now, commit the configuration file and push it to your remote repository. As discussed above, this will currently result in a large amount of output as every previous commit is exported, found to be missing a config file and then the export deleted. Eventually you will see your build and test scripts executed.
|
120
|
+
|
121
|
+
#### Example Project
|
122
|
+
|
123
|
+
Here we will demonstrate cloning the [tinyci-example](https://github.com/JonnieCache/tinyci-example) project, creating a bare clone of it to simulate our server where the tests will run, and pushing a commit to see TinyCI in action.
|
124
|
+
|
125
|
+
The example project has very simple build and test scripts written in bash.
|
126
|
+
|
127
|
+
First, create a directory to store both clones:
|
128
|
+
|
129
|
+
$ mkdir tinyci-test
|
130
|
+
$ cd tinyci-test
|
131
|
+
|
132
|
+
Clone the example project from github:
|
133
|
+
|
134
|
+
$ git clone https://github.com/JonnieCache/tinyci-example.git
|
135
|
+
|
136
|
+
Cloning into 'tinyci-example'...
|
137
|
+
remote: Counting objects: 8, done.
|
138
|
+
remote: Compressing objects: 100% (6/6), done.
|
139
|
+
remote: Total 8 (delta 0), reused 8 (delta 0), pack-reused 0
|
140
|
+
Unpacking objects: 100% (8/8), done.
|
141
|
+
|
142
|
+
Clone it again into a bare repository:
|
143
|
+
|
144
|
+
$ git clone --bare tinyci-example tinyci-example-bare
|
145
|
+
|
146
|
+
Cloning into bare repository 'tinyci-example-bare'...
|
147
|
+
done.
|
148
|
+
|
149
|
+
Install tinyci:
|
150
|
+
|
151
|
+
$ gem install tinyci
|
152
|
+
|
153
|
+
Install the tinyci hook into our bare clone:
|
154
|
+
|
155
|
+
$ cd tinyci-example-bare
|
156
|
+
$ tinyci install
|
157
|
+
|
158
|
+
[09:48:42] tinyci post-update hook installed sucessfully
|
159
|
+
|
160
|
+
Go into our initial clone and make a change:
|
161
|
+
|
162
|
+
$ cd ../tinyci-example
|
163
|
+
$ echo "foo" > bar
|
164
|
+
$ git add bar
|
165
|
+
$ git commit -m 'foobar'
|
166
|
+
|
167
|
+
[master cebb4ec] foobar
|
168
|
+
1 file changed, 1 insertion(+)
|
169
|
+
create mode 100644 bar
|
170
|
+
|
171
|
+
Add our bare repo as a remote:
|
172
|
+
|
173
|
+
$ git remote add test ../tinyci-example-bare
|
174
|
+
|
175
|
+
Push the commit and watch tinyci in action:
|
176
|
+
|
177
|
+
$ git push test master
|
178
|
+
|
179
|
+
Counting objects: 3, done.
|
180
|
+
Delta compression using up to 4 threads.
|
181
|
+
Compressing objects: 100% (2/2), done.
|
182
|
+
Writing objects: 100% (3/3), 268 bytes | 0 bytes/s, done.
|
183
|
+
Total 3 (delta 1), reused 0 (delta 0)
|
184
|
+
remote: [09:49:53] Commit: 22c36d0c1213361d06b385d2b55648985347e1f4
|
185
|
+
remote: [09:49:53] Cleaning...
|
186
|
+
remote: [09:49:53] Exporting...
|
187
|
+
remote: [09:49:53] Building...
|
188
|
+
remote: [09:49:53] Testing...
|
189
|
+
remote: [09:49:53] foo bar
|
190
|
+
remote: [09:49:53] Finished 22c36d0c1213361d06b385d2b55648985347e1f4
|
191
|
+
remote: [09:49:53] Commit: cebb4ec18b89f093c7cdeb909c2c340708052575
|
192
|
+
remote: [09:49:53] Cleaning...
|
193
|
+
remote: [09:49:53] Exporting...
|
194
|
+
remote: [09:49:53] Building...
|
195
|
+
remote: [09:49:53] Testing...
|
196
|
+
remote: [09:49:53] foo bar
|
197
|
+
remote: [09:49:53] Finished cebb4ec18b89f093c7cdeb909c2c340708052575
|
198
|
+
To ../tinyci-example-bare
|
199
|
+
22c36d0..cebb4ec master -> master
|
200
|
+
|
201
|
+
Here we are seeing TinyCI testing both the initial commit that is present in the github repo, an then the new commit that we just made. Breaking the test to see the failure output is left as an exercise for the reader.
|
202
|
+
|
203
|
+
### Contributing
|
204
|
+
|
205
|
+
Make an issue, send a pull request, you know the drill. Have a look at the [TODO section](#Limitations_TODO) for some ideas.
|
206
|
+
|
207
|
+
TinyCI has a suite of RSpec tests, please use them.
|
208
|
+
|
209
|
+
### Copyright
|
210
|
+
|
211
|
+
Copyright (c) 2018 Jonathan Davies. See [LICENSE](LICENSE) for details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/tinyci
ADDED
data/lib/pidfile.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
class PidFile
|
2
|
+
attr_reader :pidfile, :piddir, :pidpath
|
3
|
+
|
4
|
+
class DuplicateProcessError < RuntimeError; end
|
5
|
+
|
6
|
+
VERSION = '0.3.0'
|
7
|
+
|
8
|
+
DEFAULT_OPTIONS = {
|
9
|
+
:pidfile => File.basename($0, File.extname($0)) + ".pid",
|
10
|
+
:piddir => '/var/run',
|
11
|
+
}
|
12
|
+
|
13
|
+
def initialize(*args)
|
14
|
+
opts = {}
|
15
|
+
|
16
|
+
#----- set options -----#
|
17
|
+
case
|
18
|
+
when args.length == 0 then
|
19
|
+
when args.length == 1 && args[0].class == Hash then
|
20
|
+
arg = args.shift
|
21
|
+
|
22
|
+
if arg.class == Hash
|
23
|
+
opts = arg
|
24
|
+
end
|
25
|
+
else
|
26
|
+
raise ArgumentError, "new() expects hash or hashref as argument"
|
27
|
+
end
|
28
|
+
|
29
|
+
opts = DEFAULT_OPTIONS.merge opts
|
30
|
+
|
31
|
+
@piddir = opts[:piddir]
|
32
|
+
@pidfile = opts[:pidfile]
|
33
|
+
@pidpath = File.join(@piddir, @pidfile)
|
34
|
+
@fh = nil
|
35
|
+
|
36
|
+
#----- Does the pidfile or pid exist? -----#
|
37
|
+
if self.pidfile_exists?
|
38
|
+
if self.class.running?(@pidpath)
|
39
|
+
raise DuplicateProcessError, "TinyCI is already running, process #{self.class.pid} will test your commit, don't worry!"
|
40
|
+
|
41
|
+
exit! # exit without removing the existing pidfile
|
42
|
+
end
|
43
|
+
|
44
|
+
self.release
|
45
|
+
end
|
46
|
+
|
47
|
+
#----- create the pidfile -----#
|
48
|
+
create_pidfile
|
49
|
+
|
50
|
+
at_exit { release }
|
51
|
+
end
|
52
|
+
|
53
|
+
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
|
54
|
+
# Instance Methods
|
55
|
+
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
|
56
|
+
|
57
|
+
# Returns the PID, if any, of the instantiating process
|
58
|
+
def pid
|
59
|
+
return @pid unless @pid.nil?
|
60
|
+
|
61
|
+
if self.pidfile_exists?
|
62
|
+
@pid = open(self.pidpath, 'r').read.to_i
|
63
|
+
else
|
64
|
+
@pid = nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Boolean stating whether this process is alive and running
|
69
|
+
def alive?
|
70
|
+
return false unless self.pid && (self.pid == Process.pid)
|
71
|
+
|
72
|
+
self.class.process_exists?(self.pid)
|
73
|
+
end
|
74
|
+
|
75
|
+
# does the pidfile exist?
|
76
|
+
def pidfile_exists?
|
77
|
+
self.class.pidfile_exists?(pidpath)
|
78
|
+
end
|
79
|
+
|
80
|
+
# unlock and remove the pidfile. Sets pid to nil
|
81
|
+
def release
|
82
|
+
unless @fh.nil?
|
83
|
+
@fh.flock(File::LOCK_UN)
|
84
|
+
remove_pidfile
|
85
|
+
end
|
86
|
+
@pid = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
# returns the modification time of the pidfile
|
90
|
+
def locktime
|
91
|
+
File.mtime(self.pidpath)
|
92
|
+
end
|
93
|
+
|
94
|
+
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
|
95
|
+
# Class Methods
|
96
|
+
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
|
97
|
+
|
98
|
+
# Returns the PID, if any, of the instantiating process
|
99
|
+
def self.pid(path=nil)
|
100
|
+
if pidfile_exists?(path)
|
101
|
+
open(path, 'r').read.to_i
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# class method for determining the existence of pidfile
|
106
|
+
def self.pidfile_exists?(path=nil)
|
107
|
+
path ||= File.join(DEFAULT_OPTIONS[:piddir], DEFAULT_OPTIONS[:pidfile])
|
108
|
+
|
109
|
+
File.exist?(path)
|
110
|
+
end
|
111
|
+
|
112
|
+
# boolean stating whether the calling program is already running
|
113
|
+
def self.running?(path=nil)
|
114
|
+
calling_pid = nil
|
115
|
+
path ||= File.join(DEFAULT_OPTIONS[:piddir], DEFAULT_OPTIONS[:pidfile])
|
116
|
+
|
117
|
+
if pidfile_exists?(path)
|
118
|
+
calling_pid = pid(path)
|
119
|
+
end
|
120
|
+
|
121
|
+
process_exists?(calling_pid)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
# Writes the process ID to the pidfile and defines @pid as such
|
127
|
+
def create_pidfile
|
128
|
+
# Once the filehandle is created, we don't release until the process dies.
|
129
|
+
@fh = open(self.pidpath, "w")
|
130
|
+
@fh.flock(File::LOCK_EX | File::LOCK_NB) || raise
|
131
|
+
@pid = Process.pid
|
132
|
+
@fh.puts @pid
|
133
|
+
@fh.flush
|
134
|
+
@fh.rewind
|
135
|
+
end
|
136
|
+
|
137
|
+
# removes the pidfile.
|
138
|
+
def remove_pidfile
|
139
|
+
File.unlink(self.pidpath) if self.pidfile_exists?
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.process_exists?(process_id)
|
143
|
+
begin
|
144
|
+
Process.kill(0, process_id)
|
145
|
+
true
|
146
|
+
rescue Errno::ESRCH, TypeError # "PID is NOT running or is zombied
|
147
|
+
false
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'tinyci/executor'
|
2
|
+
|
3
|
+
module TinyCI
|
4
|
+
module Builders
|
5
|
+
class RktBuilder < TinyCI::Executor
|
6
|
+
def build
|
7
|
+
cmd = [
|
8
|
+
'sudo',
|
9
|
+
'rkt',
|
10
|
+
'run',
|
11
|
+
'--net=host',
|
12
|
+
'--insecure-options=image',
|
13
|
+
'--volume',
|
14
|
+
"src,kind=host,source=#{@config[:target]}/src,readOnly=false",
|
15
|
+
'--mount',
|
16
|
+
"volume=src,target=#{@config[:src_path]}",
|
17
|
+
@config[:image],
|
18
|
+
'--working-dir',
|
19
|
+
@config[:src_path],
|
20
|
+
'--exec',
|
21
|
+
@config[:command]
|
22
|
+
]
|
23
|
+
|
24
|
+
log_info "RKT build command: #{cmd.join(' ')}"
|
25
|
+
|
26
|
+
execute_stream(*cmd, label: 'build')
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'tinyci/executor'
|
2
|
+
|
3
|
+
module TinyCI
|
4
|
+
module Builders
|
5
|
+
class ScriptBuilder < TinyCI::Executor
|
6
|
+
def build
|
7
|
+
execute_stream(script_location, label: 'build', pwd: @config[:target])
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def script_location
|
13
|
+
File.join @config[:target], @config[:command]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|