mirror of
https://github.com/boostorg/build.git
synced 2026-02-17 13:42:14 +00:00
Fix/improve the symlink rule.
* new/path.jam
(make-NT, make-UNIX): Convert empty path into "."
* new/project.jam
(path-relative-to-project-location): New rule.
* new/stage.jam
(stage-target-class.construct): Use the above rule.
* new/symlink.jam
(symlink-targets.construct): Call 'set-path' on created
virtual targets.
(ln): Attempts at better handling creating symlinks in
directories.
* new/virtual-target.jam
(abstract-file-target.actual-name): If explicit path was
given, include it in grist.
* test/symlink.py: New test.
* test/test_all.py
Run new test.
[SVN r16889]
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
|
||||
exe hello : hello.cpp ;
|
||||
|
||||
#lib zlib : : <name>z <variant>release ;
|
||||
#lib zlib : : <name>z_d <variant>debug ;
|
||||
|
||||
symlink hello_debug hello_release : hello/<variant>debug hello/<variant>release ;
|
||||
symlink links/hello_release : hello/<variant>release ;
|
||||
|
||||
@@ -342,6 +342,11 @@ rule Link-action
|
||||
}
|
||||
}
|
||||
|
||||
rule gcc-Link-action
|
||||
{
|
||||
JAM_SEMAPHORE on $(<) = gcc-Link-action-semaphore ;
|
||||
}
|
||||
|
||||
# for gcc, we repeat all libraries so that dependencies are always resolved
|
||||
actions gcc-Link-action bind NEEDLIBS NEEDIMPS
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,49 +1,57 @@
|
||||
#ifndef YYERRCODE
|
||||
#define YYERRCODE 256
|
||||
#endif
|
||||
#ifndef BISON_Y_TAB_H
|
||||
# define BISON_Y_TAB_H
|
||||
|
||||
#define _BANG_t 257
|
||||
#define _BANG_EQUALS_t 258
|
||||
#define _AMPER_t 259
|
||||
#define _AMPERAMPER_t 260
|
||||
#define _LPAREN_t 261
|
||||
#define _RPAREN_t 262
|
||||
#define _PLUS_EQUALS_t 263
|
||||
#define _COLON_t 264
|
||||
#define _SEMIC_t 265
|
||||
#define _LANGLE_t 266
|
||||
#define _LANGLE_EQUALS_t 267
|
||||
#define _EQUALS_t 268
|
||||
#define _RANGLE_t 269
|
||||
#define _RANGLE_EQUALS_t 270
|
||||
#define _QUESTION_EQUALS_t 271
|
||||
#define _LBRACKET_t 272
|
||||
#define _RBRACKET_t 273
|
||||
#define ACTIONS_t 274
|
||||
#define BIND_t 275
|
||||
#define CASE_t 276
|
||||
#define DEFAULT_t 277
|
||||
#define ELSE_t 278
|
||||
#define EXISTING_t 279
|
||||
#define FOR_t 280
|
||||
#define IF_t 281
|
||||
#define IGNORE_t 282
|
||||
#define IN_t 283
|
||||
#define INCLUDE_t 284
|
||||
#define LOCAL_t 285
|
||||
#define MODULE_t 286
|
||||
#define ON_t 287
|
||||
#define PIECEMEAL_t 288
|
||||
#define QUIETLY_t 289
|
||||
#define RETURN_t 290
|
||||
#define RULE_t 291
|
||||
#define SWITCH_t 292
|
||||
#define TOGETHER_t 293
|
||||
#define UPDATED_t 294
|
||||
#define WHILE_t 295
|
||||
#define _LBRACE_t 296
|
||||
#define _BAR_t 297
|
||||
#define _BARBAR_t 298
|
||||
#define _RBRACE_t 299
|
||||
#define ARG 300
|
||||
#define STRING 301
|
||||
# ifndef YYSTYPE
|
||||
# define YYSTYPE int
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# endif
|
||||
# define _BANG_t 257
|
||||
# define _BANG_EQUALS_t 258
|
||||
# define _AMPER_t 259
|
||||
# define _AMPERAMPER_t 260
|
||||
# define _LPAREN_t 261
|
||||
# define _RPAREN_t 262
|
||||
# define _PLUS_EQUALS_t 263
|
||||
# define _COLON_t 264
|
||||
# define _SEMIC_t 265
|
||||
# define _LANGLE_t 266
|
||||
# define _LANGLE_EQUALS_t 267
|
||||
# define _EQUALS_t 268
|
||||
# define _RANGLE_t 269
|
||||
# define _RANGLE_EQUALS_t 270
|
||||
# define _QUESTION_EQUALS_t 271
|
||||
# define _LBRACKET_t 272
|
||||
# define _RBRACKET_t 273
|
||||
# define ACTIONS_t 274
|
||||
# define BIND_t 275
|
||||
# define CASE_t 276
|
||||
# define DEFAULT_t 277
|
||||
# define ELSE_t 278
|
||||
# define EXISTING_t 279
|
||||
# define FOR_t 280
|
||||
# define IF_t 281
|
||||
# define IGNORE_t 282
|
||||
# define IN_t 283
|
||||
# define INCLUDE_t 284
|
||||
# define LOCAL_t 285
|
||||
# define MODULE_t 286
|
||||
# define ON_t 287
|
||||
# define PIECEMEAL_t 288
|
||||
# define QUIETLY_t 289
|
||||
# define RETURN_t 290
|
||||
# define RULE_t 291
|
||||
# define SWITCH_t 292
|
||||
# define TOGETHER_t 293
|
||||
# define UPDATED_t 294
|
||||
# define WHILE_t 295
|
||||
# define _LBRACE_t 296
|
||||
# define _BAR_t 297
|
||||
# define _BARBAR_t 298
|
||||
# define _RBRACE_t 299
|
||||
# define ARG 300
|
||||
# define STRING 301
|
||||
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
#endif /* not BISON_Y_TAB_H */
|
||||
|
||||
1974
jam_src/jamgram.c
1974
jam_src/jamgram.c
File diff suppressed because it is too large
Load Diff
@@ -1,49 +1,57 @@
|
||||
#ifndef YYERRCODE
|
||||
#define YYERRCODE 256
|
||||
#endif
|
||||
#ifndef BISON_Y_TAB_H
|
||||
# define BISON_Y_TAB_H
|
||||
|
||||
#define _BANG_t 257
|
||||
#define _BANG_EQUALS_t 258
|
||||
#define _AMPER_t 259
|
||||
#define _AMPERAMPER_t 260
|
||||
#define _LPAREN_t 261
|
||||
#define _RPAREN_t 262
|
||||
#define _PLUS_EQUALS_t 263
|
||||
#define _COLON_t 264
|
||||
#define _SEMIC_t 265
|
||||
#define _LANGLE_t 266
|
||||
#define _LANGLE_EQUALS_t 267
|
||||
#define _EQUALS_t 268
|
||||
#define _RANGLE_t 269
|
||||
#define _RANGLE_EQUALS_t 270
|
||||
#define _QUESTION_EQUALS_t 271
|
||||
#define _LBRACKET_t 272
|
||||
#define _RBRACKET_t 273
|
||||
#define ACTIONS_t 274
|
||||
#define BIND_t 275
|
||||
#define CASE_t 276
|
||||
#define DEFAULT_t 277
|
||||
#define ELSE_t 278
|
||||
#define EXISTING_t 279
|
||||
#define FOR_t 280
|
||||
#define IF_t 281
|
||||
#define IGNORE_t 282
|
||||
#define IN_t 283
|
||||
#define INCLUDE_t 284
|
||||
#define LOCAL_t 285
|
||||
#define MODULE_t 286
|
||||
#define ON_t 287
|
||||
#define PIECEMEAL_t 288
|
||||
#define QUIETLY_t 289
|
||||
#define RETURN_t 290
|
||||
#define RULE_t 291
|
||||
#define SWITCH_t 292
|
||||
#define TOGETHER_t 293
|
||||
#define UPDATED_t 294
|
||||
#define WHILE_t 295
|
||||
#define _LBRACE_t 296
|
||||
#define _BAR_t 297
|
||||
#define _BARBAR_t 298
|
||||
#define _RBRACE_t 299
|
||||
#define ARG 300
|
||||
#define STRING 301
|
||||
# ifndef YYSTYPE
|
||||
# define YYSTYPE int
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# endif
|
||||
# define _BANG_t 257
|
||||
# define _BANG_EQUALS_t 258
|
||||
# define _AMPER_t 259
|
||||
# define _AMPERAMPER_t 260
|
||||
# define _LPAREN_t 261
|
||||
# define _RPAREN_t 262
|
||||
# define _PLUS_EQUALS_t 263
|
||||
# define _COLON_t 264
|
||||
# define _SEMIC_t 265
|
||||
# define _LANGLE_t 266
|
||||
# define _LANGLE_EQUALS_t 267
|
||||
# define _EQUALS_t 268
|
||||
# define _RANGLE_t 269
|
||||
# define _RANGLE_EQUALS_t 270
|
||||
# define _QUESTION_EQUALS_t 271
|
||||
# define _LBRACKET_t 272
|
||||
# define _RBRACKET_t 273
|
||||
# define ACTIONS_t 274
|
||||
# define BIND_t 275
|
||||
# define CASE_t 276
|
||||
# define DEFAULT_t 277
|
||||
# define ELSE_t 278
|
||||
# define EXISTING_t 279
|
||||
# define FOR_t 280
|
||||
# define IF_t 281
|
||||
# define IGNORE_t 282
|
||||
# define IN_t 283
|
||||
# define INCLUDE_t 284
|
||||
# define LOCAL_t 285
|
||||
# define MODULE_t 286
|
||||
# define ON_t 287
|
||||
# define PIECEMEAL_t 288
|
||||
# define QUIETLY_t 289
|
||||
# define RETURN_t 290
|
||||
# define RULE_t 291
|
||||
# define SWITCH_t 292
|
||||
# define TOGETHER_t 293
|
||||
# define UPDATED_t 294
|
||||
# define WHILE_t 295
|
||||
# define _LBRACE_t 296
|
||||
# define _BAR_t 297
|
||||
# define _BARBAR_t 298
|
||||
# define _RBRACE_t 299
|
||||
# define ARG 300
|
||||
# define STRING 301
|
||||
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
#endif /* not BISON_Y_TAB_H */
|
||||
|
||||
16
new/path.jam
16
new/path.jam
@@ -346,6 +346,12 @@ rule make-NT ( native )
|
||||
{
|
||||
result = /$(result) ;
|
||||
}
|
||||
|
||||
if $(native) = ""
|
||||
{
|
||||
result = "." ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
@@ -358,7 +364,15 @@ rule native-NT ( path )
|
||||
|
||||
rule make-UNIX ( native )
|
||||
{
|
||||
return [ path.join [ regex.split $(native) "/" ] ] ;
|
||||
# VP: I have no idea now 'native' can be empty here! But it can!
|
||||
if $(native) = ""
|
||||
{
|
||||
return "." ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [ path.join [ regex.split $(native) "/" ] ] ;
|
||||
}
|
||||
}
|
||||
|
||||
rule native-UNIX ( path )
|
||||
|
||||
@@ -523,6 +523,16 @@ rule target ( location )
|
||||
return $(.target.$(location)) ;
|
||||
}
|
||||
|
||||
# If 'path' is absolute, returns it.
|
||||
# Oherwise, returns the location of 'project', joined
|
||||
# with 'path'
|
||||
rule path-relative-to-project-location ( path project )
|
||||
{
|
||||
local project-location = [ attribute $(project) location ] ;
|
||||
return [ path.root $(path) $(project-location) ] ;
|
||||
}
|
||||
|
||||
|
||||
# Use/load a project.
|
||||
rule use ( id : location )
|
||||
{
|
||||
|
||||
@@ -28,10 +28,8 @@ rule stage-target-class ( name-and-dir : project : sources * : requirements * :
|
||||
local a = [ new action $(i2) : $(i) : common.copy ] ;
|
||||
$(i2).action $(a) ;
|
||||
|
||||
local pl = [ project.attribute $(self.project) location ] ;
|
||||
local path = [ path.root [ path.native $(self.name) ] $(pl) ] ;
|
||||
|
||||
$(i2).set-path $(path) ;
|
||||
$(i2).set-path [ project.path-relative-to-project-location
|
||||
$(self.name) $(self.project) ] ;
|
||||
$(i2).extra-grist stage-$(self.name) ;
|
||||
result += $(i2) ;
|
||||
}
|
||||
|
||||
@@ -56,8 +56,14 @@ rule symlink-targets (
|
||||
for local t in $(source-targets)
|
||||
{
|
||||
local s = $(self.targets[$(i)]) ;
|
||||
local vt = [ class.new file-target $(s) : [ $(t).type ] : $(self.project) ] ;
|
||||
local vt = [ class.new file-target $(s:D=) : [ $(t).type ] : $(self.project) ] ;
|
||||
$(vt).action [ class.new action $(vt) : $(t) : symlink.ln ] ;
|
||||
|
||||
# Place the symlink in the directory relative to the project
|
||||
# location, instead of placing it in the build directory.
|
||||
$(vt).set-path [ project.path-relative-to-project-location
|
||||
$(s:D) $(self.project) ] ;
|
||||
|
||||
self.virtual-targets += $(vt) ;
|
||||
i = [ numbers.increment $(i) ] ;
|
||||
}
|
||||
@@ -78,6 +84,8 @@ class.class symlink-targets : basic-target ;
|
||||
#
|
||||
# symlink one two : one two ;
|
||||
#
|
||||
# Names for symlink are relative to the project location. They cannot
|
||||
# include ".." path components.
|
||||
rule symlink (
|
||||
targets *
|
||||
: sources *
|
||||
@@ -94,12 +102,18 @@ rule ln
|
||||
local os ;
|
||||
if [ modules.peek : UNIX ] { os = UNIX ; }
|
||||
else { os ?= [ os.name ] ; }
|
||||
# Remember the path from directory where symlink will create back
|
||||
# to current dir, so that we can translate paths of the targets
|
||||
# we're symlinking to
|
||||
# Peek on LOCATE to find the directory for link
|
||||
local target-directory = [ on $(<) return $(LOCATE) ] ;
|
||||
PATH_TO_TOP on $(<) = [ path.native [ path.reverse [ path.make $(target-directory) ] ] ] ;
|
||||
ln-$(os) $(<) : $(>) ;
|
||||
}
|
||||
|
||||
actions ln-UNIX
|
||||
{
|
||||
if test -n '$(<:D)' ; then cd '$(<:D)' ; fi && ln -s '$(>)' '$(<:D=)'
|
||||
ln -s $(PATH_TO_TOP)/'$(>)' '$(<)'
|
||||
}
|
||||
|
||||
IMPORT $(__name__) : symlink : : symlink ;
|
||||
|
||||
@@ -353,11 +353,14 @@ rule abstract-file-target ( name
|
||||
local property-grist = [ property.as-path $(properties) ] ;
|
||||
grist = $(location-grist)/$(property-grist) ;
|
||||
}
|
||||
|
||||
if ! $(grist)
|
||||
{
|
||||
grist = $(location-grist) ;
|
||||
}
|
||||
if $(self.path)
|
||||
{
|
||||
grist = $(grist)@$(self.path)@ ;
|
||||
}
|
||||
if $(self.extra-grist)
|
||||
{
|
||||
grist = $(grist)/$(self.extra-grist) ;
|
||||
|
||||
31
test/symlink.py
Normal file
31
test/symlink.py
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Test the 'symlink' rule
|
||||
|
||||
from BoostBuild import Tester, dll_suffix
|
||||
import os
|
||||
t = Tester()
|
||||
|
||||
if os.name != 'posix':
|
||||
print "The symlink tests can be run on posix only"
|
||||
sys.exit(1)
|
||||
|
||||
t.write("project-root.jam", "import gcc ;")
|
||||
t.write("Jamfile", """
|
||||
exe hello : hello.cpp ;
|
||||
symlink hello_release : hello/<variant>release ;
|
||||
symlink hello_debug : hello/<variant>debug ;
|
||||
symlink links/hello_release : hello/<variant>release ;
|
||||
""")
|
||||
t.write("hello.cpp", """
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition(['hello_debug', 'hello_release', 'links/hello_release'])
|
||||
|
||||
|
||||
t.cleanup()
|
||||
@@ -34,4 +34,6 @@ import stage
|
||||
import prebuilt
|
||||
import project_dependencies
|
||||
import build_dir
|
||||
if os.name == 'posix':
|
||||
import symlink
|
||||
|
||||
|
||||
@@ -342,6 +342,11 @@ rule Link-action
|
||||
}
|
||||
}
|
||||
|
||||
rule gcc-Link-action
|
||||
{
|
||||
JAM_SEMAPHORE on $(<) = gcc-Link-action-semaphore ;
|
||||
}
|
||||
|
||||
# for gcc, we repeat all libraries so that dependencies are always resolved
|
||||
actions gcc-Link-action bind NEEDLIBS NEEDIMPS
|
||||
{
|
||||
|
||||
@@ -523,6 +523,16 @@ rule target ( location )
|
||||
return $(.target.$(location)) ;
|
||||
}
|
||||
|
||||
# If 'path' is absolute, returns it.
|
||||
# Oherwise, returns the location of 'project', joined
|
||||
# with 'path'
|
||||
rule path-relative-to-project-location ( path project )
|
||||
{
|
||||
local project-location = [ attribute $(project) location ] ;
|
||||
return [ path.root $(path) $(project-location) ] ;
|
||||
}
|
||||
|
||||
|
||||
# Use/load a project.
|
||||
rule use ( id : location )
|
||||
{
|
||||
|
||||
@@ -353,11 +353,14 @@ rule abstract-file-target ( name
|
||||
local property-grist = [ property.as-path $(properties) ] ;
|
||||
grist = $(location-grist)/$(property-grist) ;
|
||||
}
|
||||
|
||||
if ! $(grist)
|
||||
{
|
||||
grist = $(location-grist) ;
|
||||
}
|
||||
if $(self.path)
|
||||
{
|
||||
grist = $(grist)@$(self.path)@ ;
|
||||
}
|
||||
if $(self.extra-grist)
|
||||
{
|
||||
grist = $(grist)/$(self.extra-grist) ;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
|
||||
exe hello : hello.cpp ;
|
||||
|
||||
#lib zlib : : <name>z <variant>release ;
|
||||
#lib zlib : : <name>z_d <variant>debug ;
|
||||
|
||||
symlink hello_debug hello_release : hello/<variant>debug hello/<variant>release ;
|
||||
symlink links/hello_release : hello/<variant>release ;
|
||||
|
||||
31
v2/test/symlink.py
Normal file
31
v2/test/symlink.py
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Test the 'symlink' rule
|
||||
|
||||
from BoostBuild import Tester, dll_suffix
|
||||
import os
|
||||
t = Tester()
|
||||
|
||||
if os.name != 'posix':
|
||||
print "The symlink tests can be run on posix only"
|
||||
sys.exit(1)
|
||||
|
||||
t.write("project-root.jam", "import gcc ;")
|
||||
t.write("Jamfile", """
|
||||
exe hello : hello.cpp ;
|
||||
symlink hello_release : hello/<variant>release ;
|
||||
symlink hello_debug : hello/<variant>debug ;
|
||||
symlink links/hello_release : hello/<variant>release ;
|
||||
""")
|
||||
t.write("hello.cpp", """
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition(['hello_debug', 'hello_release', 'links/hello_release'])
|
||||
|
||||
|
||||
t.cleanup()
|
||||
@@ -34,4 +34,6 @@ import stage
|
||||
import prebuilt
|
||||
import project_dependencies
|
||||
import build_dir
|
||||
if os.name == 'posix':
|
||||
import symlink
|
||||
|
||||
|
||||
@@ -28,10 +28,8 @@ rule stage-target-class ( name-and-dir : project : sources * : requirements * :
|
||||
local a = [ new action $(i2) : $(i) : common.copy ] ;
|
||||
$(i2).action $(a) ;
|
||||
|
||||
local pl = [ project.attribute $(self.project) location ] ;
|
||||
local path = [ path.root [ path.native $(self.name) ] $(pl) ] ;
|
||||
|
||||
$(i2).set-path $(path) ;
|
||||
$(i2).set-path [ project.path-relative-to-project-location
|
||||
$(self.name) $(self.project) ] ;
|
||||
$(i2).extra-grist stage-$(self.name) ;
|
||||
result += $(i2) ;
|
||||
}
|
||||
|
||||
@@ -56,8 +56,14 @@ rule symlink-targets (
|
||||
for local t in $(source-targets)
|
||||
{
|
||||
local s = $(self.targets[$(i)]) ;
|
||||
local vt = [ class.new file-target $(s) : [ $(t).type ] : $(self.project) ] ;
|
||||
local vt = [ class.new file-target $(s:D=) : [ $(t).type ] : $(self.project) ] ;
|
||||
$(vt).action [ class.new action $(vt) : $(t) : symlink.ln ] ;
|
||||
|
||||
# Place the symlink in the directory relative to the project
|
||||
# location, instead of placing it in the build directory.
|
||||
$(vt).set-path [ project.path-relative-to-project-location
|
||||
$(s:D) $(self.project) ] ;
|
||||
|
||||
self.virtual-targets += $(vt) ;
|
||||
i = [ numbers.increment $(i) ] ;
|
||||
}
|
||||
@@ -78,6 +84,8 @@ class.class symlink-targets : basic-target ;
|
||||
#
|
||||
# symlink one two : one two ;
|
||||
#
|
||||
# Names for symlink are relative to the project location. They cannot
|
||||
# include ".." path components.
|
||||
rule symlink (
|
||||
targets *
|
||||
: sources *
|
||||
@@ -94,12 +102,18 @@ rule ln
|
||||
local os ;
|
||||
if [ modules.peek : UNIX ] { os = UNIX ; }
|
||||
else { os ?= [ os.name ] ; }
|
||||
# Remember the path from directory where symlink will create back
|
||||
# to current dir, so that we can translate paths of the targets
|
||||
# we're symlinking to
|
||||
# Peek on LOCATE to find the directory for link
|
||||
local target-directory = [ on $(<) return $(LOCATE) ] ;
|
||||
PATH_TO_TOP on $(<) = [ path.native [ path.reverse [ path.make $(target-directory) ] ] ] ;
|
||||
ln-$(os) $(<) : $(>) ;
|
||||
}
|
||||
|
||||
actions ln-UNIX
|
||||
{
|
||||
if test -n '$(<:D)' ; then cd '$(<:D)' ; fi && ln -s '$(>)' '$(<:D=)'
|
||||
ln -s $(PATH_TO_TOP)/'$(>)' '$(<)'
|
||||
}
|
||||
|
||||
IMPORT $(__name__) : symlink : : symlink ;
|
||||
|
||||
@@ -346,6 +346,12 @@ rule make-NT ( native )
|
||||
{
|
||||
result = /$(result) ;
|
||||
}
|
||||
|
||||
if $(native) = ""
|
||||
{
|
||||
result = "." ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
@@ -358,7 +364,15 @@ rule native-NT ( path )
|
||||
|
||||
rule make-UNIX ( native )
|
||||
{
|
||||
return [ path.join [ regex.split $(native) "/" ] ] ;
|
||||
# VP: I have no idea now 'native' can be empty here! But it can!
|
||||
if $(native) = ""
|
||||
{
|
||||
return "." ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [ path.join [ regex.split $(native) "/" ] ] ;
|
||||
}
|
||||
}
|
||||
|
||||
rule native-UNIX ( path )
|
||||
|
||||
Reference in New Issue
Block a user