Skip to content

Commit 71eefeb

Browse files
authored
functionality to quickly activate the project you want!!! (#11)
* findproject and quick activate functions * safety in quick activate * add tests for quick activate and findproject * test git=false as well. * docs for the new functions
1 parent ea8a00d commit 71eefeb

File tree

4 files changed

+122
-11
lines changed

4 files changed

+122
-11
lines changed

LICENSE

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,36 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4747
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4848
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4949
SOFTWARE.
50+
51+
---
52+
53+
The function `findproject` uses Julia's Base.current_project function. License:
54+
55+
The Julia language is licensed under the MIT License. The "language" consists
56+
of the compiler (the contents of src/), most of the standard library (base/),
57+
and some utilities (most of the rest of the files in this repository).
58+
For more info see https://julialang.org/license
59+
60+
> Copyright (c) 2009-2018: Jeff Bezanson, Stefan Karpinski, Viral B. Shah,
61+
> and other contributors:
62+
>
63+
> https://github.com/JuliaLang/julia/contributors
64+
>
65+
> Permission is hereby granted, free of charge, to any person obtaining
66+
> a copy of this software and associated documentation files (the
67+
> "Software"), to deal in the Software without restriction, including
68+
> without limitation the rights to use, copy, modify, merge, publish,
69+
> distribute, sublicense, and/or sell copies of the Software, and to
70+
> permit persons to whom the Software is furnished to do so, subject to
71+
> the following conditions:
72+
>
73+
> The above copyright notice and this permission notice shall be
74+
> included in all copies or substantial portions of the Software.
75+
>
76+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
77+
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
78+
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
79+
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
80+
> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
81+
> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
82+
> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

docs/src/project.md

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ Part of the functionality of DrWatson is creating and navigating through a proje
55
For this to work, you only need to follow these rules:
66

77
1. **Your science project is also a Julia project defined by a `Project.toml` file.**
8-
2. **You first activate this project environment before running any code.** This can be done in multiple ways:
9-
* by doing `Pkg.activate("path/to/project")` programmatically
10-
* by using the startup flag `--project path` when starting Julia
11-
* by setting the [`JULIA_PROJECT`](https://docs.julialang.org/en/latest/manual/environment-variables/#JULIA_PROJECT-1) environment variable
12-
3. **You use the functions `scriptdir`, `datadir`, etc. from DrWatson** (see [Navigating the Project](@ref))
8+
2. **You first activate this project environment before running any code.** See [Activating a Project](@ref) for ways to do this.
9+
3. **You use the functions `scriptdir`, `datadir`, etc. from DrWatson** (see [Navigating a Project](@ref))
1310

1411
## Default Project Setup
1512

@@ -31,9 +28,9 @@ ShowFile(dirname(pathof(DrWatson))*"/defaults/project_structure.txt") # hide
3128
### `src` vs `scripts`
3229
Seems like `src` and `scripts` folders have pretty similar functionality. However there is a distinction between these two. You can follow these mental rules to know where to put `file.jl`:
3330

34-
1. If upon `include("file.jl")` there is _anything_ being produced, be it data files, plots or even output to the console, then it should be in `scripts`.
35-
2. If it is functionality used across multiple files or pipelines, it should be in `src`.
36-
3. `src` should only contain files that define functions or types but not output anything. You can also organize `src` to be a Julia package, or contain multiple Julia packages.
31+
* If upon `include("file.jl")` there is _anything_ being produced, be it data files, plots or even output to the console, then it should be in `scripts`.
32+
* If it is functionality used across multiple files or pipelines, it should be in `src`.
33+
* `src` should only contain files that define functions or types but not output anything. You can also organize `src` to be a Julia package, or contain multiple Julia packages.
3734

3835
## Initializing a Project
3936

@@ -42,7 +39,29 @@ To initialize a project as described in the [Default Project Setup](@ref) sectio
4239
initialize_project
4340
```
4441

45-
## Navigating the Project
42+
## Activating a Project
43+
This part of DrWatson's functionality requires you to have your scientific project (and as a consequence, the Julia project) activated.
44+
This can be done in multiple ways:
45+
1. doing `Pkg.activate("path/to/project")` programmatically
46+
2. using the startup flag `--project path` when starting Julia
47+
3. by setting the [`JULIA_PROJECT`](https://docs.julialang.org/en/latest/manual/environment-variables/#JULIA_PROJECT-1) environment variable
48+
4. using the functions [`quickctivate`](@ref) and [`findproject`](@ref) offered by DrWatson.
49+
50+
We highly recommend the fourth approach. Here is how it works: the function [`quickactivate`](@ref) activates a project given some path by recursively searching the path and its parents for a valid `Project.toml` file. Typically you put this function in your script files like so:
51+
```julia
52+
using DrWatson # and any other package you use
53+
quickactivate(@__DIR__)
54+
# or
55+
quickactivate(@__DIR__, "Best project in the WORLLDD")
56+
```
57+
where the second optional argument can assert if the activated project matches the name you provided, see below for more.
58+
59+
```@docs
60+
quickactivate
61+
findproject
62+
```
63+
64+
## Navigating a Project
4665
To be able to navigate the project consistently, DrWatson provides the following functions:
4766
```julia
4867
datadir() = projectdir()*"data/"

src/project_setup.jl

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
##########################################################################################
44
export projectdir, datadir, srcdir, plotsdir, scriptdir
55
export projectname
6+
export findproject, quickactivate
67

78
"""
89
projectdir()
@@ -20,6 +21,59 @@ Return the name of the currently active project.
2021
"""
2122
projectname() = Pkg.REPLMode.promptf()[2:end-7]
2223

24+
"""
25+
findproject(path = pwd()) -> project_path
26+
Recursively search `path` and its parents for a valid Julia project file.
27+
If it is found return its path, otherwise issue a warning and return
28+
`nothing`.
29+
30+
The function stops searching if it hits either the home directory or
31+
the root directory.
32+
"""
33+
function findproject(dir::AbstractString = pwd())
34+
# look for project file in current dir and parents
35+
home = homedir()
36+
while true
37+
for proj in Base.project_names
38+
file = joinpath(dir, proj)
39+
Base.isfile_casesensitive(file) && return dir
40+
end
41+
# bail at home directory
42+
dir == home && break
43+
# bail at root directory
44+
old, dir = dir, dirname(dir)
45+
dir == old && break
46+
end
47+
@warn "Could not find find a project file by recursively checking "*
48+
"given `path` and its parents. Returning `nothing` instead."
49+
return nothing
50+
end
51+
52+
"""
53+
quickactivate(path [, name::String])
54+
Activate the project found by [`findproject`](@ref) of the `path`.
55+
Optionally check if `name` is the same as the activated project's name.
56+
If it is not, throw an error.
57+
58+
This function is _first_ activating the project and _then_ checking if
59+
it matches the `name`.
60+
"""
61+
function quickactivate(path, name = nothing)
62+
projectpath = findproject(path)
63+
projectpath === nothing && return nothing
64+
Pkg.activate(projectpath)
65+
if !(name === nothing) && projectname() != name
66+
error(
67+
"The activated project did not match asserted name. Current project "*
68+
"name is $(projectname()) while the asserted name is $name."
69+
)
70+
end
71+
return nothing
72+
end
73+
74+
75+
76+
2377
##########################################################################################
2478
# Project directory and setup management
2579
##########################################################################################
@@ -71,8 +125,7 @@ function initialize_project(path, name = basename(path);
71125
if git; repo = LibGit2.init(path); end
72126
git && LibGit2.commit(repo, "Initial commit")
73127
Pkg.activate(path)
74-
# Pkg.add("DrWatson")#Uncomment when the package is released
75-
Pkg.add("Pkg")
128+
Pkg.add("DrWatson")
76129

77130
# Default folders
78131
for p in DEFAULT_PATHS

test/project_tests.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ name = "lala"
88
initialize_project(path)
99

1010
@test projectname() == path
11+
@test findproject(@__DIR__) === nothing
1112
for p in DrWatson.DEFAULT_PATHS
1213
@test ispath(joinpath(path, p))
1314
end
@@ -31,8 +32,13 @@ z = read((path*"/Project.toml"), String)
3132
@test occursin("[\"George\", \"Nick\"]", z)
3233

3334
initialize_project(path, name; force = true, authors = "Sophia", git = false)
35+
@test !isdir(joinpath(path, ".git"))
3436
z = read((path*"/Project.toml"), String)
3537
@test occursin("[\"Sophia\"]", z)
3638

39+
cd(path)
40+
@test findproject(pwd()) == pwd()
41+
cd()
42+
3743
rm(path, recursive = true, force = true)
3844
@test !isdir(path)

0 commit comments

Comments
 (0)