Completed
Pull Request — master (#520)
by Sean
03:19
created

FetchJob::tearDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
class FetchJob extends DeploynautJob {
4
5
	public $args;
6
7
	/**
8
	 * @var DNProject
9
	 */
10
	protected $project;
11
12
	/**
13
	 * @var DeploynautLogFile
14
	 */
15
	protected $log;
16
17
	/**
18
	 * @var string
19
	 */
20
	protected $user;
21
22
	/**
23
	 * @global array $databaseConfig
24
	 */
25
	public function setUp() {
26
		global $databaseConfig;
27
		DB::connect($databaseConfig);
28
29
		$this->updateStatus('Started');
30
		chdir(BASE_PATH);
31
	}
32
33
	public function perform() {
34
		set_time_limit(0);
35
36
		if(!empty($this->args['logfile'])) {
37
			$this->log = new DeploynautLogFile($this->args['logfile']);
38
		}
39
40
		$this->project = DNProject::get()->byId($this->args['projectID']);
41
		if(!($this->project && $this->project->exists())) {
42
			throw new RuntimeException(sprintf('Project ID %s not found', $this->args['projectID']));
43
		}
44
45
		$this->user = DNData::inst()->getGitUser() ?: null;
46
47
		// Disallow concurrent git fetches on the same project.
48
		// Only consider fetches started in the last 30 minutes (older jobs probably got stuck)
49
		try {
50
			if(!empty($this->args['fetchID'])) {
51
				$runningFetches = DNGitFetch::get()
52
					->filter(array(
53
						'ProjectID' => $this->project->ID,
54
						'Status' => array('Queued', 'Started'),
55
						'Created:GreaterThan' => strtotime('-30 minutes')
56
					))
57
					->exclude('ID', $this->args['fetchID']);
58
59
				if($runningFetches->count()) {
60
					$runningFetch = $runningFetches->first();
61
					$message = sprintf(
62
						'Another fetch is in progress (started at %s by %s)',
63
						$runningFetch->dbObject('Created')->Nice(),
64
						$runningFetch->Deployer()->Title
65
					);
66
					if($this->log) {
67
						$this->log->write($message);
68
					}
69
					throw new RuntimeException($message);
70
				}
71
			}
72
73
			// Decide whether we need to just update what we already have
74
			// or initiate a clone if no local repo exists.
75
			if($this->project->repoExists() && empty($this->args['forceClone'])) {
0 ignored issues
show
Bug introduced by
The method repoExists() does not exist on DataObject. Did you maybe mean exists()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
76
				$this->fetchRepo();
77
			} else {
78
				$this->cloneRepo();
79
			}
80
		} catch(Exception $e) {
81
			if($this->log) {
82
				$this->log->write($e->getMessage());
83
			}
84
			throw $e;
85
		}
86
	}
87
88
	protected function fetchRepo() {
89
		$this->runCommand(
90
			'git fetch -p origin +refs/heads/*:refs/heads/* --tags',
91
			$this->project->getLocalCVSPath()
92
		);
93
	}
94
95
	protected function cloneRepo() {
96
		if(file_exists($this->project->getLocalCVSPath())) {
97
			$this->runCommand(sprintf(
98
				'rm -rf %s',
99
				escapeshellarg($this->project->getLocalCVSPath())
100
			));
101
		}
102
103
		$this->runCommand(sprintf(
104
			'git clone --bare -q %s %s',
105
			escapeshellarg($this->project->CVSPath),
106
			escapeshellarg($this->project->getLocalCVSPath())
107
		));
108
	}
109
110
	/**
111
	 * Run a shell command.
112
	 *
113
	 * @param string $command The command to run
114
	 * @param string|null $workingDir The working dir to run command in
115
	 * @throws RuntimeException
116
	 */
117
	protected function runCommand($command, $workingDir = null) {
118
		if(!empty($this->user)) {
119
			$command = sprintf('sudo -u %s %s', $this->user, $command);
120
		}
121
		if($this->log) {
122
			$this->log->write(sprintf('Running command: %s', $command));
123
		}
124
		$process = new \Symfony\Component\Process\Process($command, $workingDir);
125
		$process->setEnv($this->project->getProcessEnv());
126
		$process->setTimeout(1800);
127
		$process->run();
128
		if(!$process->isSuccessful()) {
129
			throw new RuntimeException($process->getErrorOutput());
130
		}
131
	}
132
133
	/**
134
	 * @param string $status
135
	 * @global array $databaseConfig
136
	 */
137
	protected function updateStatus($status) {
138
		global $databaseConfig;
139
		DB::connect($databaseConfig);
140
141
		if(!empty($this->args['fetchID'])) {
142
			$fetch = DNGitFetch::get()->byID($this->args['fetchID']);
143
			if($fetch && $fetch->exists()) {
144
				$fetch->Status = $status;
145
				$fetch->write();
146
			}
147
		}
148
	}
149
150
}
151