Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

"""Functions to manage the installation of dependencies.""" 

 

import os 

import functools 

import datetime 

import logging 

 

from . import common, system 

from .models import load_config, Config, Source 

 

log = logging.getLogger(__name__) 

 

 

def restore_cwd(func): 

@functools.wraps(func) 

def wrapped(*args, **kwargs): 

cwd = os.getcwd() 

result = func(*args, **kwargs) 

os.chdir(cwd) 

return result 

return wrapped 

 

 

def init(): 

"""Create a new configuration file for the project.""" 

success = False 

 

config = _find_config() 

 

if config: 

msg = "Configuration file already exists: {}".format(config.path) 

common.show(msg, color='error') 

 

else: 

config = Config() 

source = Source(name="sample_dependency", 

repo="https://github.com/githubtraining/hellogitworld") 

config.sources.append(source) 

source = source.lock(rev="ebbbf773431ba07510251bb03f9525c7bab2b13a") 

config.sources_locked.append(source) 

config.save() 

 

msg = "Created sample configuration file: {}".format(config.path) 

common.show(msg, color='success') 

success = True 

 

msg = "To edit this configuration file, run: gitman edit" 

common.show(msg, color='message') 

 

return success 

 

 

@restore_cwd 

def install(*names, root=None, depth=None, 

force=False, fetch=False, clean=True): 

"""Install dependencies for a project. 

 

Optional arguments: 

 

- `*names`: optional list of dependency directory names to filter on 

- `root`: specifies the path to the root working tree 

- `depth`: number of levels of dependencies to traverse 

- `force`: indicates uncommitted changes can be overwritten and 

script errors can be ignored 

- `fetch`: indicates the latest branches should always be fetched 

- `clean`: indicates untracked files should be deleted from dependencies 

 

""" 

log.info("%sInstalling dependencies: %s", 

'force-' if force else '', 

', '.join(names) if names else '<all>') 

count = None 

 

config = _find_config(root) 

 

76 ↛ 77line 76 didn't jump to line 77, because the condition on line 76 was never true if config: 

common.newline() 

common.show("Installing dependencies...", color='message', log=False) 

common.newline() 

count = config.install_dependencies( 

*names, update=False, depth=depth, 

force=force, fetch=fetch, clean=clean, 

) 

 

if count: 

_run_scripts(*names, depth=depth, force=force, _config=config) 

 

return _display_result("install", "Installed", count) 

 

 

@restore_cwd 

def update(*names, root=None, depth=None, 

recurse=False, force=False, clean=True, lock=None): # pylint: disable=redefined-outer-name 

"""Update dependencies for a project. 

 

Optional arguments: 

 

- `*names`: optional list of dependency directory names to filter on 

- `root`: specifies the path to the root working tree 

- `depth`: number of levels of dependencies to traverse 

- `recurse`: indicates nested dependencies should also be updated 

- `force`: indicates uncommitted changes can be overwritten and 

script errors can be ignored 

- `clean`: indicates untracked files should be deleted from dependencies 

- `lock`: indicates actual dependency versions should be recorded 

 

""" 

log.info("%s dependencies%s: %s", 

'Force updating' if force else 'Updating', 

', recursively' if recurse else '', 

', '.join(names) if names else '<all>') 

count = None 

 

config = _find_config(root) 

 

116 ↛ 117line 116 didn't jump to line 117, because the condition on line 116 was never true if config: 

common.newline() 

common.show("Updating dependencies...", color='message', log=False) 

common.newline() 

count = config.install_dependencies( 

*names, update=True, depth=depth, 

recurse=recurse, force=force, fetch=True, clean=clean, 

) 

 

if count and lock is not False: 

common.show("Recording installed versions...", 

color='message', log=False) 

common.newline() 

config.lock_dependencies(*names, obey_existing=lock is None) 

 

if count: 

_run_scripts(*names, depth=depth, force=force, _config=config) 

 

return _display_result("update", "Updated", count) 

 

 

def _run_scripts(*names, depth=None, force=False, _config=None): 

"""Run post-install scripts. 

 

Optional arguments: 

 

- `*names`: optional list of dependency directory names filter on 

- `depth`: number of levels of dependencies to traverse 

- `force`: indicates script errors can be ignored 

 

""" 

assert _config, "'_config' is required" 

 

common.show("Running scripts...", color='message', log=False) 

common.newline() 

_config.run_scripts(*names, depth=depth, force=force) 

 

 

@restore_cwd 

def display(*, root=None, depth=None, allow_dirty=True): 

"""Display installed dependencies for a project. 

 

Optional arguments: 

 

- `root`: specifies the path to the root working tree 

- `depth`: number of levels of dependencies to traverse 

- `allow_dirty`: causes uncommitted changes to be ignored 

 

""" 

log.info("Displaying dependencies...") 

count = None 

 

config = _find_config(root) 

 

170 ↛ 171line 170 didn't jump to line 171, because the condition on line 170 was never true if config: 

common.newline() 

common.show("Displaying current dependency versions...", 

color='message', log=False) 

common.newline() 

config.log(datetime.datetime.now().strftime("%F %T")) 

count = 0 

for identity in config.get_dependencies(depth=depth, 

allow_dirty=allow_dirty): 

count += 1 

config.log("{}: {} @ {}", *identity) 

config.log() 

 

return _display_result("display", "Displayed", count) 

 

 

@restore_cwd 

def lock(*names, root=None): 

"""Lock current dependency versions for a project. 

 

Optional arguments: 

 

- `*names`: optional list of dependency directory names to filter on 

- `root`: specifies the path to the root working tree 

 

""" 

log.info("Locking dependencies...") 

count = None 

 

config = _find_config(root) 

 

if config: 

common.newline() 

common.show("Locking dependencies...", color='message', log=False) 

common.newline() 

count = config.lock_dependencies(*names, obey_existing=False) 

common.dedent(level=0) 

 

return _display_result("lock", "Locked", count) 

 

 

@restore_cwd 

def delete(*, root=None, force=False): 

"""Delete dependencies for a project. 

 

Optional arguments: 

 

- `root`: specifies the path to the root working tree 

- `force`: indicates uncommitted changes can be overwritten 

 

""" 

log.info("Deleting dependencies...") 

count = None 

 

config = _find_config(root) 

 

226 ↛ 227line 226 didn't jump to line 227, because the condition on line 226 was never true if config: 

common.newline() 

common.show("Checking for uncommitted changes...", 

color='message', log=False) 

common.newline() 

count = len(list(config.get_dependencies(allow_dirty=force))) 

common.dedent(level=0) 

common.show("Deleting all dependencies...", color='message', log=False) 

common.newline() 

config.uninstall_dependencies() 

 

return _display_result("delete", "Deleted", count, allow_zero=True) 

 

 

def show(*names, root=None): 

"""Display the path of an installed dependency or internal file. 

 

- `name`: dependency name or internal file keyword 

- `root`: specifies the path to the root working tree 

 

""" 

log.info("Finding paths...") 

 

config = _find_config(root) 

 

if not config: 

log.error("No configuration found") 

return False 

 

for name in names or [None]: 

common.show(config.get_path(name), color='path') 

 

return True 

 

 

def edit(*, root=None): 

"""Open the confuration file for a project. 

 

Optional arguments: 

 

- `root`: specifies the path to the root working tree 

 

""" 

log.info("Launching configuration...") 

 

config = _find_config(root) 

 

if not config: 

log.error("No configuration found") 

return False 

 

return system.launch(config.path) 

 

 

def _find_config(root=None, *, cwd=None): 

if cwd is None: 

cwd = os.getcwd() 

log.info("Current directory: %s", cwd) 

 

if root: 

log.info("Specified root: %s", root) 

else: 

root = _find_root(cwd=cwd) 

 

log.info("Searching for config...") 

path = cwd 

while path != os.path.dirname(path): 

log.debug("Checking path: %s", path) 

config = load_config(path) 

if config: 

return config 

elif path == root: 

break 

else: 

path = os.path.dirname(path) 

 

return None 

 

 

def _find_root(base=None, *, cwd=None): 

if cwd is None: 

cwd = os.getcwd() 

log.info("Current directory: %s", cwd) 

 

if base: 

root = os.path.abspath(base) 

log.info("Specified root: %s", root) 

 

else: 

log.info("Searching for root...") 

path = cwd 

root = None 

while path != os.path.dirname(path): 

log.debug("Checking path: %s", path) 

if '.git' in os.listdir(path): 

root = path 

break 

path = os.path.dirname(path) 

 

if root: 

log.info("Found root: %s", root) 

else: 

root = cwd 

log.warning("No root found, default: %s", root) 

 

return root 

 

 

def _display_result(present, past, count, allow_zero=False): 

"""Convert a command's dependency count to a return status. 

 

>>> _display_result("sample", "Sampled", 1) 

True 

 

>>> _display_result("sample", "Sampled", None) 

False 

 

>>> _display_result("sample", "Sampled", 0) 

False 

 

>>> _display_result("sample", "Sampled", 0, allow_zero=True) 

True 

 

""" 

350 ↛ 352line 350 didn't jump to line 352, because the condition on line 350 was never false if count is None: 

log.warning("No dependencies to %s", present) 

elif count == 1: 

log.info("%s 1 dependency", past) 

else: 

log.info("%s %s dependencies", past, count) 

 

357 ↛ 358line 357 didn't jump to line 358, because the condition on line 357 was never true if count: 

return True 

359 ↛ 362line 359 didn't jump to line 362, because the condition on line 359 was never false elif count is None: 

return False 

else: 

assert count == 0 

return allow_zero