Skip to content

Commit

Permalink
all: add support for @BUILD_DATE, @BUILD_TIME and `@BUILD_TIMESTA…
Browse files Browse the repository at this point in the history
…MP`, all using v.util.get_build_time(), and overridable through SOURCE_DATE_EPOCH (#22213)
  • Loading branch information
spytheman authored Sep 14, 2024
1 parent 0d980a4 commit 4c68f85
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 2 deletions.
20 changes: 19 additions & 1 deletion doc/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -5851,8 +5851,19 @@ that are substituted at compile time:
next to the nearest v.mod file (as a string).
- `@VMODROOT` => will be substituted with the *folder*,
where the nearest v.mod file is (as a string).
- `@BUILD_DATE` => replaced with the build date, for example '2024-09-13' .
- `@BUILD_TIME` => replaced with the build time, for example '12:32:07' .
- `@BUILD_TIMESTAMP` => replaced with the build timestamp, for example '1726219885' .
Note: `@BUILD_DATE`, `@BUILD_TIME`, `@BUILD_TIMESTAMP` represent times in the UTC timezone.
By default, they are based on the current time of the compilation/build. They can be overriden
by setting the environment variable `SOURCE_DATE_EPOCH`. That is also useful while making
releases, since you can use the equivalent of this in your build system/script:
`export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) ;` , and then use `@BUILD_DATE` etc.,
inside your program, when you for example print your version information to users.
See also https://reproducible-builds.org/docs/source-date-epoch/ .
That allows you to do the following example, useful while debugging/logging/tracing your code:
The compile time pseudo variables allow you to do the following
example, which is useful while debugging/logging/tracing your code:
```v
eprintln(@LOCATION)
Expand All @@ -5871,6 +5882,13 @@ A program that prints its own source code (a quine):
print($embed_file(@FILE).to_string())
```
A program that prints the time when it was built:
```v
import time
println('This program, was compiled at ${time.unix(@BUILD_TIMESTAMP.i64()).format_ss_milli()} .')
```
> [!NOTE]
> you can have arbitrary source code in the file, without problems, since the full file
> will be embedded into the executable, produced by compiling it. Also note that printing
Expand Down
9 changes: 9 additions & 0 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -3640,6 +3640,15 @@ fn (mut c Checker) at_expr(mut node ast.AtExpr) ast.Type {
}
node.val = hash
}
.build_date {
node.val = util.stable_build_time.strftime('%Y-%m-%d')
}
.build_time {
node.val = util.stable_build_time.strftime('%H:%M:%S')
}
.build_timestamp {
node.val = util.stable_build_time.unix().str()
}
.unknown {
c.error('unknown @ identifier: ${node.name}. Available identifiers: ${token.valid_at_tokens}',
node.pos)
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/parser/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,9 @@ fn (mut p Parser) at() ast.AtExpr {
'@VMODROOT' { token.AtKind.vmodroot_path }
'@VMODHASH' { token.AtKind.vmod_hash }
'@VROOT' { token.AtKind.vroot_path } // deprecated, use @VEXEROOT or @VMODROOT
'@BUILD_DATE' { token.AtKind.build_date }
'@BUILD_TIME' { token.AtKind.build_time }
'@BUILD_TIMESTAMP' { token.AtKind.build_timestamp }
else { token.AtKind.unknown }
}
expr := ast.AtExpr{
Expand Down
15 changes: 15 additions & 0 deletions vlib/v/tests/comptime/comptime_at_test.v
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import time
import v.pref

struct TestStruct {
Expand Down Expand Up @@ -173,3 +174,17 @@ fn test_at_location() {
assert @LOCATION.contains('comptime_at_test.v:')
assert @LOCATION.ends_with('main.test_at_location')
}

fn test_at_build_date_time_timestamp() {
bd := dump(@BUILD_DATE)
bt := dump(@BUILD_TIME)
bts := dump(@BUILD_TIMESTAMP)
assert bd.len > 0
assert bt.len > 0
assert bd.count('-') == 2
assert bt.count(':') == 2
assert bts.len > 0
assert bts.i64() > 1_000_000_000
now_utc := dump(time.utc().unix())
assert now_utc >= bts.i64()
}
5 changes: 4 additions & 1 deletion vlib/v/token/token.v
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ pub enum AtKind {
vexeroot_path
file_path_line_nr
location
build_date
build_time
build_timestamp
}

pub const assign_tokens = [Kind.assign, .decl_assign, .plus_assign, .minus_assign, .mult_assign,
Expand All @@ -193,7 +196,7 @@ pub const assign_tokens = [Kind.assign, .decl_assign, .plus_assign, .minus_assig

pub const valid_at_tokens = ['@VROOT', '@VMODROOT', '@VEXEROOT', '@FN', '@METHOD', '@MOD', '@STRUCT',
'@VEXE', '@FILE', '@LINE', '@COLUMN', '@VHASH', '@VCURRENTHASH', '@VMOD_FILE', '@VMODHASH',
'@FILE_LINE', '@LOCATION']
'@FILE_LINE', '@LOCATION', '@BUILD_DATE', '@BUILD_TIME', '@BUILD_TIMESTAMP']

pub const token_str = build_token_str()

Expand Down
1 change: 1 addition & 0 deletions vlib/v/util/util.v
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub fn tabs(n int) string {
return if n >= 0 && n < const_tabs.len { const_tabs[n] } else { '\t'.repeat(n) }
}

pub const stable_build_time = get_build_time()
// get_build_time returns the current build time, while taking into account SOURCE_DATE_EPOCH
// to support transparent reproducible builds. See also https://reproducible-builds.org/docs/source-date-epoch/
// When SOURCE_DATE_EPOCH is not set, it will return the current UTC time.
Expand Down

0 comments on commit 4c68f85

Please sign in to comment.